home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Mac Tech Notes (DocViewer) / TN-Graphics / TN-Graphics
Encoding:
Text File  |  1993-01-05  |  1.6 MB  |  5,976 lines  |  [ONLN/HLX2]

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. 32-Bit QuickDraw:  Version 1.2 Features
  2. Imaging    M.IM.32BitQD
  3. Written by:    Guillermo Ortiz    April 1990
  4. This Technical Note describes the changes and enhancements to 32-Bit QuickDraw from version 1.0 (as shipped on the original Color Disk) to version 1.2, which ships with System Software 6.0.5 and later.  This Note assumes familiarity with Inside Macintosh, Volume V, Color QuickDraw, and 32-Bit QuickDraw release notes.
  5. 32-Bit QuickDraw
  6. Version 1.0 of 32-Bit QuickDraw shipped in May 1989 in response to the growing need for Color QuickDraw support for direct color devices and pictures (PICT2) and video boards for large-screen monitors which require 32-bit addressing for black and white operation.  This original version of 32-Bit QuickDraw was a separate file that had to be copied manually into the System Folder.  With the introduction of the Macintosh IIci, Apple put 32-Bit QuickDraw into ROM.  Now System Software 6.0.5 and later offer 32-Bit QuickDraw as an integral part of the System Software which can be installed by the standard Installer (although the file is still separate).
  7. This Note describes the changes and enhancements in version 1.2 of 32-Bit QuickDraw from version 1.0.  Beginning with version 1.2, QuickDraw functionality is identical on all Color QuickDraw machines, including all the performance improvements which were originally only available in the IIci ROM.
  8. New Features (In No Particular Order)
  9. PICTs Contain Font Name Information
  10. Every time you draw text inside of an _OpenPicture and _ClosePicture pair, QuickDraw stores the name of the current font and uses it when playing back the picture.  The opcode used to save this information is $002C and its data is as follows:
  11.     PictFontInfo = Record
  12.                      length   : Integer;    { length of data in bytes }
  13.                      fontID   : Integer;    { ID in the source system }
  14.                      fontName : Str255;
  15.                    END;
  16. QuickDraw only saves this information one time for each font used in a picture.  When QuickDraw plays back a picture, it uses the fontID as a reference into the list of font names which are used to set the correct font on the target system.
  17. For example, the following code:
  18.     GetFNum('Venice', theFontID);    { Set a font before opening PICT}
  19.     TextFont(theFontID);
  20.     pHand2 := OpenPicture (pictRect);
  21.         MoveTo(20,20);
  22.         DrawString(' Better be Venice');
  23.         GetFNum('Geneva', theFontID);
  24.         TextFont(theFontID);
  25.         MoveTo(20,40);
  26.         DrawString('Geneva');
  27.         GetFNum('New York', theFontID);
  28.         TextFont(theFontID);
  29.         MoveTo(20,60);
  30.         DrawString('New York');
  31.         GetFNum('Geneva', theFontID);
  32.         TextFont(theFontID);
  33.         MoveTo(20,80);
  34.         DrawString('Geneva');
  35.     ClosePicture; 
  36. generates a picture containing font information like this:
  37.     OpCode 0x002C {9, 
  38.         "0005 0656 656E 6963 65"}              /* save current font     */
  39.     TxFont 'venice'
  40.     DHDVText {20, 20, " Better be Venice"}
  41.     OpCode 0x002C {9,                          /* save next font name   */
  42.         "0003 0647 656E 6576 61"}
  43.     TxFont 'geneva'
  44.     DVText {20, "Geneva"}
  45.     OpCode 0x002C {11,                         /* ditto                 */
  46.         "0002 084E 6577 2059 6F72 6B"}
  47.     TxFont 'newYork'
  48.     DVText {20, "New York"}
  49.     TxFont 'geneva'                            /* second Geneva does not
  50.                                                  need another $002C guy */
  51.     DVText {20, "Geneva"}
  52. This feature works regardless of the type of picture being saved, including old style PICTs in a black and white port.  Using _OpenCPicture instead of _OpenPicture to start a recording session results in the same functionality.
  53. Direct PixPat Structures Now Supported
  54. QuickDraw now supports 16-bit and 32-bit per pixel PixPat structures (patType = 1).  In addition, it now supports a new patType (3) which uses dithering whenever 16-bit or 32-bit  pixel patterns are displayed on indexed devices.
  55. Direct 'cicn' Resources Now Supported
  56. QuickDraw now supports 16-bit and 32-bit per pixel 'cicn' resources.  The 16-bit per pixel is particularly cool since you save the space required for an 8-bit 'clut'.
  57. GWorlds Can Now Be Allocated in MultiFinder Temporary Memory
  58. You can now use the new useMFTempBit (bit 2) in a call to NewGWorld as an option to allocate pixels in MultiFinder temporary memory.  In addition, you can now allocate screen buffers in MultiFinder temporary memory using the following routine, defined in Pascal and C:
  59. FUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN;
  60.                               VAR gdh: GDHandle;
  61.                                VAR offscreenPixMap: PixMapHandle): QDErr;
  62.              INLINE $203C,$000E, $0015,$AB1D; { Move.L #$000E0015,D0
  63.                                                _QDOffscreen
  64.                                              }
  65. pascal QDErr NewTempScreenBuffer (Rect *globalRect, BOOLEAN purgeable,
  66.                               GDHandle *gdh,
  67.                               PixMapHandle *offscreenPixMap)
  68.              ={0x203C,0x000E,0x0015,0xAB1D}; 
  69. Indexed to Indexed Dithering
  70. _CopyBits now supports the ditherCopy transfer mode whenever the destination device is between one and eight bits per pixel, regardless of the depth of the source image.  With this support, an eight-bit image can now be approximated on a one-bit or a four-bit device by using error diffusion.  Furthermore, an eight-bit image could also be dithered to a different set of 256 colors or a four-bit image could be dithered to an eight-bit device that does not have the desired colors.
  71. 32-Bit Addressed PixMap Structures
  72. Version 1.2 defines a new pmVersion (baseAddr32 = 4) for 32-bit pointer baseAddr values.  The baseAddr of such PixMap structures is treated as a 32-bit address, so no stripping or address translation is performed on it in 32-bit mode.  This is a specially useful feature when the base address of a PixMap points to a NuBus™ address, for example in a video grabber board.
  73. A new call, Pixmap32Bit, is now available to inquire if a given PixMap requires 32-bit addressing.
  74. FUNCTION Pixmap32Bit(pmh:pixMapHandle):Boolean;
  75.     INLINE $203C,$0004, $0016,$AB1D; { Move.L #$00040016,D0
  76.                                       _QDOffscreen
  77.                                     }
  78. pascal BOOLEAN Pixmap32Bit(pixMapHandle pmh)
  79.     = {0x203C,0x0004, 0x0016,0xAB1D}; 
  80. Updated GetPixBaseAddress
  81. Version 1.2 updates GetPixBaseAddress to return the address of any PixMap.  The routine does the right address translation or stripping for all PixMap structures, including screen devices, unlocked GWorlds, and 32-bit addressed PixMap structures.  The address it returns is only valid in 32-bit addressing mode. Also unless the PixMap is locked and made unpurgeable, the address returned by GetPixBaseAddress is only valid until any call to QuickDraw or the toolbox is made.
  82. _CopyBits from Screen Devices
  83. The picture recording mechanism has changed so that if you call _CopyBits while recording a picture with the source PixMap being a screen device, the data is correctly accumulated into the picture.  Note that if the screen being copied is not the main screen, then the PixMap must be a 32-bit addressed PixMap.  No auxiliary screen buffer is allocated if the source rectangle covers only one screen.
  84. New Picture Recording Trap
  85. Version 1.2 adds a new call, _OpenCPicture, to create pictures that contain information regarding the native resolution of the recorded image.  When QuickDraw draws this picture, it scales the image to the resolution of the target device.  Applications that need to scale the images directly can also access this information.
  86. FUNCTION OpenCPicture(VAR CPictInfo:CPictRecord):PicHandle;
  87.     INLINE $AA20;
  88. pascal PicHandle OpenCPicture(CPictRecord *CPictInfo)
  89.     =  0xAA20;
  90. where
  91. struct CPictRecord {
  92.       Rect CPicFrame;           /* Bounding rect of Picture at native resolution */
  93.       Fixed CPicHRes;           /* native horizontal resolution in pixels/inch   */
  94.       Fixed CPicVRes;           /* native vertical resolution in pixels/inch     */
  95.       short CPicVersion;        /* version of this PICT info set to -2           */
  96.       short reserved;           /* for future expansion set to zero              */
  97.       long reserved;            /* for future expansion set to zero              */
  98.         };
  99. The new picture header data looks like the following:
  100. Size in bytes    Name    Description
  101.     2    picSize    low word of picture size
  102.     8    picFrame    bounding box at 72 dpi
  103. Picture Header
  104. 2    version op    version opcode = $0011
  105. 2    version    version number = $02FF
  106. 2    Header op    header opcode  = $0C00
  107. 2    version    -2 for PICTs created with _OpenCPicture
  108. 2    reserved
  109. 4    HRes    native horizontal resolution (Fixed)
  110. 4    VRes    native vertical resolution (Fixed)
  111. 8    SrcRect    native source rectangle
  112. 4    reserved
  113. The following is a sample PICT created with _OpenCPicture:
  114.     00 48                          /* low word of size              */
  115.     00 00 00 00 00 7D 00 7D        /* picFrame at 72 dpi            */
  116.     00 11                          /* PICT version opcode           */
  117.     02 FF                          /* version number                */
  118.     0C 00                          /* PICT header Opcode            */
  119.     FF FE                          /* PICT version -2               */
  120.     00 00                          /* reserved                      */
  121.     01 20 00 00                    /* HRes (Fixed)                  */
  122.     01 20 00 00                    /* VRes (Fixed)                  */
  123.     00 00 00 00 01 F4 01 F4        /* picFrame at native resolution */
  124.     00 00 00 00                    /* reserved                      */
  125.     /* picture data follows                                         */
  126.     00 FF                          /* end of picture opcode         */
  127. Random Notes
  128. For information on bug fixes in the System Software 6.0.5 release of 32-Bit QuickDraw (version 1.2), please refer to the System Software 6.0.5 Change History, which is available on the Developer CD Series, AppleLink in the Developer Services Bulletin Board (Developer Services: Macintosh Developer Technical Support: System Software), and the Apple FTP site on the Internet in the ~ftp/pub/dts/sw.license.
  129. Note that the dispatching mechanism for the new _QDOffscreen calls is slightly different than previously documented; it now requires that the high word passed in D0 contain the total length of the parameters (in bytes).  The reason for this change is that if the call is made in an earlier version of 32-Bit QuickDraw, the system can strip the parameters from the stack and return QDError set to the caller (instead of crashing).
  130. Further Reference:
  131. •    Inside Macintosh, Volume V, Color QuickDraw
  132. •    32-Bit QuickDraw Release Notes (available from APDA)
  133. •    System Software 6.0.5 Change History
  134. •    d e v e l o p, Issue I
  135. NuBus is a trademark of Texas Instruments.
  136. Basic QuickDraw Q&As
  137. Imaging    M.IM.BasicQD.Q&As
  138. Revised by:    Developer Support Center    October 1992
  139. Written by:    Developer Support Center    October 1990
  140. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  141. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  142. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  143. Sending PostScript via PostScriptHandle PicComment
  144. Written:    5/1/90
  145. Last reviewed:    10/9/91
  146. If I use the PostScriptHandle PicComment to send PostScript code to the LaserWriter driver, do I need to open a picture and then draw the picture to the driver, or can I just use the PicComment with no picture open while drawing to the printer’s grafPort?
  147. ___
  148. You don’t need to create a picture with your PicComment in it and draw the picture to the driver. The best method for sending PostScript code to the LaserWriter is to use the PostScriptHandle PicComment documented in the Macintosh Technical Note #91, “Optimizing for the LaserWriter—Picture Comments,” as shown below.
  149. PrOpenPage(...)
  150. { Send some QuickDraw so that the Printing Manager gets a }
  151. { chance to define the clipping region. }
  152. PenSize(0,0); 
  153. MoveTo(0,0);
  154. LineTo(0,0); 
  155. PenSize(1,1); 
  156. PicComment(PostScriptBegin, 0, NIL);
  157. { QuickDraw representation of graphic. }
  158. MoveTo(100, 100);
  159. LineTo(200, 200);
  160. { PostScript representation of graphic. }
  161. thePSHandle^^ := '100 100 moveto 200 200 lineto stroke';
  162. PicComment(PostScriptHandle, GetHandleSize(thePSHandle),
  163.               thePSHandl);
  164. PicComment(PostScriptEnd, 0, NIL);
  165. PrClosePage(...)
  166. The above code prints a line on any type of printer, PostScript or not. The first MoveTo/LineTo combination is required to give the LaserWriter driver a chance to define a clipping region. The LaserWriter driver replaces the grafProcs record in the grafPort returned from PrOpenDoc. In order for the LaserWriter driver to get execution time, you must execute a QuickDraw drawing routine that calls one of the grafProcs. In this case, the MoveTo/LineTo combination calls the StdLine grafProc. When StdLine executes, it notices that the grafPort has been reinitialized, and therefore initializes the clipping region for the port. Until the MoveTo/LineTo combination is executed, the clipping region for the port is set to (0,0,0,0). If PostScript code is sent via the PostScriptHandle PicComment before executing any QuickDraw routines, all PostScript operations will be clipped to (0,0,0,0).
  167. The next thing that’s done is to send the PostScriptBegin PicComment. This comment is recognized only by PostScript printer drivers. When the driver receives this comment, it saves the current state of the PostScript device (by executing the PostScript gsave operator), then disables all QuickDraw drawing operations. This way, the QuickDraw representation of the graphic will be ignored by PostScript devices. In the above example, the second MoveTo/LineTo combination is executed only on non-PostScript devices.
  168. The next PicComment is PostScriptHandle, which tells the driver that the data in thePSHandle is to be sent to the device as PostScript code. The driver then passes this code unchanged to the PostScript device for execution. The PostScriptHandle comment is recognized only by PostScript printer drivers.
  169. The last PicComment, PostScriptEnd, tells the driver to restore the previous state of the device (via a PostScript grestore call), and to enable QuickDraw drawing operations.
  170. Since most PicComments are ignored by QuickDraw devices, only the QuickDraw representation is printed. Since PostScriptBegin tells PostScript drivers to ignore QuickDraw operations, only the PostScript representation is printed on PostScript devices. This is a truly device-independent method for providing both PostScript and QuickDraw representations of a document.
  171. Macintosh PICT-to-PostScript conversion
  172. Written:    8/3/90
  173. Last reviewed:    10/8/91
  174. How do I convert PICT format data to PostScript in my printer driver?
  175. ___
  176. Converting PICT files to PostScript involves a detailed understanding of both bitmaps (or pixmaps) and the graphics state in PostScript, which is a data structure defining the context in which other graphic operators in PostScript execute. If you don’t know PostScript, the following manuals are a must:
  177. •    PostScript Language Tutorial and Cookbook (Addison-Wesley) is an introduction to PostScript. • PostScript Language Reference Manual (Addison-Wesley).
  178. •    PostScript Language Program Design (Addison-Wesley) details designing efficient PostScript programs. It has a lot of useful sample programs on topics like writing a print spooler.
  179. You need to convert all the QuickDraw operations in a PICT to corresponding PostScript operations. To get a feel for this conversion, you can analyze the PostScript dump from a LaserWriter to see how it converts a PICT to PostScript. Under System 6.x, a PostScript dump can be obtained by pressing Command-K while printing. Under System 7.0, you can get a dump by selecting the PostScript File option in the Print dialog.
  180. Some areas of QuickDraw, such as transfer modes, do not have a correspondence in PostScript. The PostScript imaging model is designed so that all areas of a page affected by an image are marked as if with opaque paint. Using image masks can help. See the Graphics chapter in the PostScript reference manual.
  181. PICT-to-PostScript conversion can be a long process, especially if one is unfamiliar with PostScript. Using the above books and the PostScript dump from the LaserWriter (but ONLY as a general guide) should help.
  182. Calling InitCursor instead of SetCursor
  183. Written:    10/23/90
  184. Last reviewed:    2/20/91
  185. Is it legal to call InitCursor instead of SetCursor(arrow) when I want to set the cursor to an arrow (after my normal one-time program initialization code, in my UpdateCursor routine)? The only reason I'd want to do such a skanky thing is to save code. Calling a trap with no parameters is less code than one with parameters. What, exactly, if anything, does InitCursor do besides setting the cursor to an arrow and setting the cursor level to zero?
  186. ___
  187. There's no problem at all with this, as long as you are aware that the hidden, busy, and obscured states are cleared when you call InitCursor, so if the cursor was hidden or obscured for good reason it'll suddenly reappear. It also gets the arrow from QuickDraw, of course, but that's not a problem.
  188. PICT fontName opcode
  189. Written:    10/31/90
  190. Last reviewed:    2/20/91
  191. Is there an up-to-date canonical source for PICT opcodes? In “Night of the Living Disc,” as far as I can see, the only list of PICT opcodes is in the Macintosh Tech Note “QuickDraw’s Internal Picture Definition” which does not mention opcode $2C. It appears that opcode $2C concerns font names. I recall seeing a patch for PictDetective named "fontnameop" or something like that. However I can't be sure that $2C is the only new opcode.
  192. ___
  193. The fontName opcode is documented in the Technical Note “32-Bit QuickDraw: Version 1.2 Features.” Note also that since the introduction of 32-Bit QuickDraw there are two more bitmap opcodes for direct RGB PixMaps $009A (DirectBitsRect) and $009B (DirectBitsRgn). The QuickDraw section of Inside Macintosh Volume VI has all these opcodes listed in a single place, making it easier to get the necessary info. Here is the info on font names and pictures from the "32-Bit QuickDraw..." Tech Note:
  194. PICTs Contain Font Name Information
  195. Every time you draw text inside of an _OpenPicture and _ClosePicture pair,
  196. QuickDraw stores the name of the current font and uses it when playing back
  197. the picture. The opcode used to save this information is $002C and its data is
  198. as follows:
  199.    PictFontInfo = Record
  200.                     length   : Integer;    { length of data in bytes }
  201.                     fontID   : Integer;    { ID in the source system }
  202.                     fontName : Str255;
  203.                   END;
  204. QuickDraw saves this information only one time for each font used in a picture. When QuickDraw plays back a picture, it uses the fontID as a reference into the list of font names which are used to set the correct font on the target system.
  205. For example, the following code:
  206.    GetFNum('Venice', theFontID);    { Set a font before opening PICT}
  207.    TextFont(theFontID);
  208.    pHand2 := OpenPicture (pictRect);
  209.        MoveTo(20,20);
  210.        DrawString(' Better be Venice');
  211.        GetFNum('Geneva', theFontID);
  212.        TextFont(theFontID);
  213.        MoveTo(20,40);
  214.        DrawString('Geneva');
  215.        GetFNum('New York', theFontID);
  216.        TextFont(theFontID);
  217.        MoveTo(20,60);
  218.        DrawString('New York');
  219.        GetFNum('Geneva', theFontID);
  220.        TextFont(theFontID);
  221.        MoveTo(20,80);
  222.        DrawString('Geneva');
  223.    ClosePicture;
  224. generates a picture containing font information like this:
  225.    OpCode 0x002C {9,
  226.        "0005 0656 656E 6963 65"}          /* save current font     */
  227.    TxFont 'venice'
  228.    DHDVText {20, 20, " Better be Venice"}
  229.    OpCode 0x002C {9,                      /* save next font name   */
  230.        "0003 0647 656E 6576 61"}
  231.    TxFont 'geneva'
  232.    DVText {20, "Geneva"}
  233.    OpCode 0x002C {11,                     /* ditto                  */
  234.        "0002 084E 6577 2059 6F72 6B"}
  235.    TxFont 'newYork'
  236.    DVText {20, "New York"}
  237.    TxFont 'geneva'                        /* second Geneva does not
  238.                                           need another $002C guy */
  239.    DVText {20, "Geneva"}
  240. This feature works regardless of the type of picture being saved, including old style PICTs in a black-and-white port. Using _OpenCPicture instead of _OpenPicture to start a recording session results in the same functionality.
  241. X-Refs:
  242. Inside Macintosh Volume VI
  243. Macintosh Technical Note “QuickDraw's Internal Picture Definition”
  244. Macintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  245. Using PicComments to rotate text
  246. Written:    11/28/90
  247. Last reviewed:    12/19/90
  248. I have a PostScript routine (using TextBegin/TextEnd) to generate bitmapped rotated text on the screen (which can be later printed on QuickDraw printers). Why do I get duplicate text? I get both bitmapped rotated text and PostScript rotated text when I print on the LaserWriter II, and both bitmapped rotated text and horizontal text on the ImageWriter. When I make a machine dependent check (check type of printer) and call the proper printing procedure, it works fine. Because of the speed and memory considerations of generating the rotated bitmapped text (especially at 300 dpi), is there a way to ensure that the printer will use the PostScript BEFORE generating the bitmap?
  249. ___
  250. We will use the following Macintosh PicComments to hide your QuickDraw calls from the LaserWriter, but the ImageWriter will use them:
  251. PostScriptBegin
  252.  >> Put your CopyBits and QuickDraw calls to image your rotated
  253.  >> bitmapped text here....
  254. PostScriptEnd
  255. By wrapping your QuickDraw code within the PostScriptBegin and PostScriptEnd PicComments, the code will be ignored by the LaserWriter, but the ImageWriter will use the QuickDraw calls. Basically, the PostScriptBegin and PostScriptEnd PicComments tell the LaserWriter driver to turn “off” QuickDraw. In the ImageWriter case, the ImageWriter does not understand the PicComments. Therefore, it will use the QuickDraw calls to create and image your bitmapped text. 
  256. Now, we need to use the rotation PicComments to rotate the text on the LaserWriter, but have the ImageWriter ignore the code:
  257. Rect  zeroRect;
  258. SetRect (&zeroRect, 0, 0, 0, 0);
  259. TextBegin
  260. TextCenter
  261.       ClipRect (&zeroRect);
  262.       >> Draw your text to be rotated on the LaserWriter....
  263.       ClipRect (&rPageRect);
  264. TextEnd
  265. Wrapping your text drawing call(s) between the ClipRect calls will ensure that the text is drawn only on the LaserWriter. Setting the ClipRect to zero tells the ImageWriter to ignore all QuickDraw calls until the ClipRect is reset to something “real” (actually, a zero ClipRect prevents QuickDraw from drawing anything). After we have completed drawing the rotated text, we reset the ClipRect to the dimensions of rPage (that is, rPage is the image-able area of the currently selected printer—see Inside Macintosh, Volume II, page 150). This will allow all of your normal drawing to continue on the ImageWriter and LaserWriter. If you did not reset the ClipRect after the TextEnd call, nothing would be drawn on the ImageWriter or LaserWriter.
  266. Using dithered drawing mode with QuickDraw
  267. Written:    11/28/90
  268. Last reviewed:    12/19/90
  269. When I draw a 32-bit Macintosh PICT image from a file to an 8-bit port via an offscreen GWorld, I use dither mode in the CopyBits call and the results are quite impressive. If there is not enough memory to allocate the GWorld, I draw the image directly to the port. But since there does not seem to be any way to tell QuickDraw to use dithered drawing mode, the image looks horrible.
  270. Do you have any suggestions? I have installed bottleneck procs to allow DrawPicture to get its data from the file instead of the handle in memory. Is there a way, while in the bottlenecks, to find the CopyBits call that comes from the picture and force it to use dithered mode instead of source mode? I don’t want to try and parse the PICT myself, but I thought that maybe a QuickDraw global could be modified in my StdBits proc to force dithered drawing for that operation only?
  271. ___
  272. You can install a StdBits or bitsProc bottleneck procedure to get all the CopyBits calls when the picture is being played back. One of the parameters to the StdBits call is the mode. You can install a procedure that saves the current mode, and then passes ditherMode to the original StdBits proc. This is all you should need to do. It’s been done here so we know it works, only not in any form that can be sent to you as sample code at this time.
  273. Code for reversing Macintosh PICT images
  274. Written:    3/4/91
  275. Last reviewed:    8/30/91
  276. Is there a simple way to put PICT images up in mirror image format, or is there sample code showing how to flip an offscreen bitmap?
  277. ___
  278. There is no easy way to do this, nor do we have sample code showing how to flip an offscreen bitmap. Indeed, the best way to do what you want is to draw it to an offscreen pixel map and reverse it.
  279. If you are using Color QuickDraw, always draw it to an 8-bit-per-pixel offscreen bitmap, and then the reverse is a very simple task. Here is some sample Pascal code that might roughly do what you want, with the following assumptions:
  280.     1. You are going to add error checking where appropriate.
  281.     2. Rowbytes correspond exactly to pixel width of the port.
  282.     3. The port is 8 bits deep.
  283.     4. You add the code to make this sketch work.
  284.     5. The origin of your offscreen port is (0,0).
  285. Procedure FlipScanLine(theV:Integer; thePort:cGrafPtr);
  286. { Given any scan line number in the indicated port, this routine will flip }
  287. { that scan line horizontally. This routine assumes that you have made     }
  288. { sure that scan line theV exists. }
  289. type ScanLn=Packed Array [0..0] of Byte;
  290.    ScanPtr=^ScanLine;
  291. var thePixMap:PixMapPtr;
  292.    Index,Size:Integer;
  293.    ThisScanLine:ScanPtr;
  294.    TempPixel:Byte;
  295. Begin
  296.  thePixMap:=thePort^.PortPixMap^;
  297. { First create a pointer to the scan line we are currently reversing. }
  298.  ThisScanLine:=ScanPtr(thePixMap^.BaseAddr);
  299.  ThisScanLine:=ScanPtr(ord4(ThisScanLine)+(thePixMap^.RowBytes*theV));
  300. { Now simply reverse all the bytes. }
  301. { The scan line is simply an array [0..RowBytes] of Byte, and since this is }
  302. { 8 bits per pixel, each one is a single pixel.}
  303.  Size:=thePixMap^.RowBytes;
  304.  For Index:=0 to (Size div 2) do
  305.   begin
  306.    tempPixel:=ThisScanLine^[Index];
  307.    ThisScanLine^[Index]:=ThisScanLine[Size-Index-1];
  308.    ThisScanLine^[Index]:=tempPixel;
  309.   end;
  310. end;
  311. This same procedure can be used also to swap a 1-, 2- or 4-bit-per-pixel pixmap if you add a function that accepts a byte and swaps the pixels in it.
  312. Use srcOr instead of srcCopy for Macintosh text drawing
  313. Written:    6/4/91
  314. Last reviewed:    10/9/91
  315. DrawText with srcCopy takes six times as long as with srcOr now that my Macintosh is running System 7. Why is this so slow? Is this a bug in System 7?
  316. ___
  317. It’s true that srcCopy is slower than srcOr when handling text, especially in color mode. This loss in speed occurs because CopyBits is a lot smarter than it used to be. It can handle foreground and background colors a lot better, but that improvement came at the cost of speed. Our recommended method for drawing text is to erase before drawing, and use srcOr to draw, not srcCopy. Alternatively, you could draw colorized text in srcOr mode off screen and then use CopyBits to draw it on the screen in srcCopy mode without colorization.
  318. Techniques for graying Macintosh text
  319. Written:    6/3/91
  320. Last reviewed:    8/1/91
  321. How do I draw grayed-out text on the Macintosh, like the text for disabled buttons or menu items?
  322. ___
  323. There are currently two different kinds of grayed text: First, there’s 
  324. “patterned” gray, where every other dot is missing. This really only looks good with Chicago or other heavy fonts and was always used for graying out menus and controls in system software through 6.0.x, and is still used in 7.0 when the screen is set to less than 4 bits deep. This is done by first drawing the text in a normal, srcCopy transfer mode. Then a gray rectangle is drawn over the text using the patBic mode. This “erases” half the bits in the text, and is rapid enough that there is very rarely any flicker.
  325. The second kind of text is the actually gray text, which is used in System 7 on screens that are 4 bits deep or deeper for menus, controls, and other grayed text. To draw this text, just call GetGray (as documented on page 17-27 of Inside Macintosh, Volume VI) to get an appropriate gray. Then draw the text in that color.
  326. Updating Macintosh cursor without mouse competition
  327. Written:    6/12/91
  328. Last reviewed:    8/1/91
  329. How can I programmatically move the Macintosh mouse without the real mouse interfering?
  330. ___
  331. The real answer to your question is twofold: First, you can do exactly what you want to do with the sample included below. HOWEVER, this is not a good thing to do, it would be better if you took the solution used in Apple’s Guided Tour disks: Always hide the cursor and then decouple the cursor from the mouse. Then, instead of using the system’s cursor, simply draw your own “cursor” using QuickDraw and treat it as a little animated bitmap on the screen. This avoids all the problems that you have with the mouse competing. (Apple does update the mouse globals with the mouse position so that other things function correctly.)
  332. Now, as promised, here is the way to do what you want using the real cursor. As you have discovered, setting the crsrCouple variable to false prohibits the mouse from affecting the cursor; unfortunately, it also prohibits the jcrsrTask routine from drawing the cursor. The solution to this is to set crsr couple to true, call the cursor drawing routine jCrsrTask yourself, and then set the crsrCouple variable to false, as shown below:
  333. procedure callcrsr;
  334.               inline $2078 ,$08EE ,$4E90;
  335. {            move.L    jcrsrTask,A0
  336.             jsr    (A0)                            }
  337. Procedure FudgeMouse;
  338. type    PointPtr=^Point;
  339. var        RawMouse:PointPtr;
  340.         MTemp:PointPtr;
  341.         RandPt:Point;
  342.         CrsrNew:ptr;
  343.         CrsrCouple:ptr;
  344.         fred:Longint;
  345.        
  346. begin
  347.         RawMouse:=PointPtr($82C);
  348.         MTemp:=PointPtr($828);
  349.         CrsrNew:=ptr($8CE);
  350.         CrsrCouple:=ptr($8CF);
  351.         RandPt:=RawMouse^;
  352.         repeat
  353.             RandPt.h:=RandPt.h+1;
  354.             RandPt.V:=RandPt.v+1;
  355.             RawMouse^:=RandPt;
  356.             MTemp^:=RandPt;
  357.             CrsrNew^:=1;
  358.             CrsrCouple^:=1;
  359.             callCrsr;
  360.             crsrCouple^:=0;
  361.             repeat until fred<tickCount;
  362.             fred:=tickCount+3;
  363.         until Button;
  364.         crsrCouple^:=1;
  365. end;
  366. System 7 QuickDraw DrawText performance
  367. Written:    11/4/91
  368. Last reviewed:    11/27/91
  369. We’ve noticed that using DrawText is much slower in System 7, especially when drawing in color (anything other than black on white). What can be done to restore the drawing speed to System 6 levels?
  370. ___
  371. A QuickDraw function like DrawString or DrawText will be slower under certain circumstances in System 7 than System 6. Specifically, if you are drawing in srcCopy mode and you colorize the text—that is, foreground color is not black and background color is not white (Inside Macintosh Volume VI, page 17-16)—then QuickDraw really slows down as you have noticed. SOMETIMES, the speed of drawing is 6 times as slow as System 6.
  372. The cause of this slowness is a known System 7 bug. The bug has concerned the engineers greatly and will be responded to in an appropriate manner in the future.
  373. There are a few workarounds: One, you can avoid using the srcCopy mode and use the default srcOr mode instead. However, this is not a real workaround, since you may have essential reasons to use srcCopy. The other option is to create an offscreen pixmap or GWorld and perform a DrawText with srcOr to this GWorld with colorization. Then, you can perform a CopyBits from the offscreen to the screen with srcCopy mode and no colorization. Using CopyBits will not cost you much time. Again, this is a workaround and is not ideal. 
  374. The srcOr is a bit slower than in System 6.0.x, but it does not have a bug; rather it is a side effect of system enhancements. The slow speed is a trade-off taken to receive the host of other benefits.
  375. Macintosh animation samples
  376. Written:    11/6/91
  377. Last reviewed:    11/6/91
  378. Do you have an example of flicker-free animation on the Macintosh?
  379. ___
  380. We have some good stuff that’s written in MPW Pascal. It’s DTS Sample Code #16, OffSample, and this uses some routines defined in DTS Sample Code #15, OffScreen. Also, the System 7.0 CD sample code folder contains a smaller sample called “GMonde” that uses GWorlds.
  381. CopyBits bug and workaround
  382. Written:    6/26/91
  383. Last reviewed:    8/13/91
  384. Has anyone run across what I’m told is a bug in CopyBits? It works like this: In the deep, dark workings of CopyBits, some routine tries to read the two bytes preceding the baseAddress of the source PixMap. If the baseAddress is at the start of a card’s NuBus space and there isn’t a card filling the adjacent space, this causes a bus error! Has anyone found a good workaround?
  385. ___
  386. The short answer is: you’re right. QuickDraw inadvertently reads from memory below the base address of a pixmap. The workaround is to place the video base address 32 bytes into the RAM on the card; if the card you’re using doesn’t have this workaround, there’s nothing you can do other than making sure there’s a card in the next-lower slot.
  387. Macintosh picture (PICT) 90-degree rotation
  388. Written:    7/23/91
  389. Last reviewed:    8/30/91
  390. The trick for rotating a Macintosh QuickDraw picture 90 degrees is to intercept all bottlenecks and exchange the x and y coordinates. Then, call OpenPicture to receive the rotated picture, call DrawPicture(unrotatedPicture), and then call ClosePicture on the rotated picture. You’re done! QuickDraw spins out the DrawPicture call into its component parts, but runs each component through the bottlenecks first, so they get rotated (by YOUR bottleneck intercepts) and stuck into the new picture, already rotated.
  391. Here‘s a bottleneck intercept for StdLine that rotates a PICT composed entirely of Line commands (which depend on the current pen position):
  392. procedure MyLineProc(newPt: point);
  393. var
  394.   tempV : integer;
  395. begin
  396.   tempV := thePort^.pnLoc.v;     { Swap current pen location coordinates }
  397.   thePort^.pnLoc.v := thePort^.pnLoc.h;
  398.   thePort^.pnLoc.h := tempV;
  399.   
  400.   tempV := newPt.v;          { Swap destination pen location coordinates }
  401.   newPt.v := newPt.h;
  402.   newPt.h := tempV;
  403.   
  404.   StdLine(newPt);
  405.   
  406.   tempV := thePort^.pnLoc.v;  { Restore current pen location coordinates }
  407.   thePort^.pnLoc.v := thePort^.pnLoc.h;
  408.   thePort^.pnLoc.h := tempV;
  409. end;
  410. Notice that the start coordinates as well as the destination coordinates must be swapped before calling StdLine. The resulting pen location is swapped back again after the operation, so the port looks like it should if unrotated drawing were performed. For things that don’t depend on the current pen location, things are simplified a little bit.
  411. You’ll still need bitmap rotation code for the StdBits and StdText intercepts.You might do StdText by setting the port to an offscreen one you create earlier, calling QuickDraw’s StdText, and then calling your bitmap rotation code to copy it into the destination.
  412. Macintosh QuickDraw and pen characteristic routines
  413. Written:    8/12/91
  414. Last reviewed:    11/6/91
  415. When generating pictures and then looking at the corresponding Macintosh PICT file, we notice that QuickDraw is optimizing PnMode, PnPat, and PnSize. Can you tell us how to stop QuickDraw from optimizing, and how to know when QuickDraw will optimize?
  416. ___
  417. QuickDraw does not optimize away new pen characteristic routines, but it does insert them into pictures just before a drawing routine that uses the pen rather than place them where they are called. Therefore, you may not see your new pen characteristic routine until later in a picture when it is about to be used. Opcodes for pen characteristics are inserted into the picture when they are changed from the previous time they’re used.
  418. Detecting whether application window is partially hidden
  419. Written:    9/26/92
  420. Last reviewed:    1/27/92
  421. We draw directly to the screen to gain the fastest possible animation speed, and when we need compatibility—such as when windows overlap or for multiple screens—we do use CopyBits. How do we tell whether the window is hidden or that the visible part is not rectangular?
  422. ___
  423. If your window is covered partially by another applications window or if your layer has been hidden by the process menu, the visRgn of your window’s grafport will not be the portRect anymore. (Keep in mind that if you scroll by modifying the portRect of the grafport, then you’ll have to do a more complex calculation...) Here is a small Pascal routine that returns this information:
  424. Function UseCopyBits(thePort:grafptr):Boolean;
  425. begin
  426.    
  427.      UseCopyBits:= NOT( (thePort^.VisRgn^^.rgnSize=10) and
  428.         (thePort^.visRgn^^.RgnBBox=thePort^.PortRect) );
  429. end;
  430. The rect strucRgn^^.rgnBBox will be zero for a visible window if the system 
  431. has hidden the application.
  432. How to tell whether GetPictInfo is available
  433. Written:    12/16/91
  434. Last reviewed:    2/24/92
  435. How do you determine whether the function GetPictInfo is available? Gestalt doesn’t seem to have the right stuff?!
  436. ___
  437. To determine whether the GetPictInfo routine is available, check the system version number with the Gestalt function. The GetPictInfo routine is available under system software version 7.0 and later. Use the Gestalt selector gestaltSystemVersion to determine the version of the system currently running. In most cases you shouldn’t rely on the system version to determine if features are available. However, in this case, this is the only way to determine if the Picture Utilities Package is available.
  438. See Inside Macintosh Volume VI page 3-42 for information on using Gestalt to check the System version number. See Inside Macintosh Volume VI page 18-3 for information on the Picture Utilities Package.
  439. For example, the following C function will determine if the GetPictInfo call is available:
  440.     #include <GestaltEQU.h>
  441.     Boolean IsGetPictInfoAvail()
  442.     {
  443.       OSErr err;
  444.       long feature;
  445.          err = Gestalt(gestaltSystemVersion,&feature);
  446.       /*-- check for system 7 and above --*/
  447.       return (feature >= 0x00000700);
  448.     }
  449. or, if you prefer Pascal:
  450.     function IsGetPictInfoAvail: Boolean;
  451.     var
  452.         err: OSErr;
  453.         feature: longint;
  454.     begin
  455.         err := Gestalt(gestaltSystemVersion, feature);
  456.         (*-- check for system 7 and above --*)
  457.         IsGetPictInfoAvail := (feature >= $00000700);
  458.     end;
  459. GrafPort patStretch: valid values
  460. Written:    12/19/91
  461. Last reviewed:    2/6/92
  462. I’d like to know more about that PatStretch field inside a GrafPort or CGrafPort. If I stuff a values in PatStretch(4) then nothing happens; prints look the same, even using a standard bottleneck. Please tell me how I can get this to work.
  463. ___
  464. PatStretch only works with values of 2 or 3. With any other value, it defaults to no stretching. The “2” case was created because of the ImageWriter (72->144 dpi) situation. The “3” case was added to support the ImageWriter LQ and the AppleFax modem.
  465. So why wasn’t a “4” (72->300 dpi) handler added for the LaserWriter driver? Good question. Somehow or other it was decided that pattern stretching for the LaserWriter driver would be done completely by the driver itself. The LaserWriter driver actually does pattern stretching by using a pattern 4 times as large, rather than 4.17. In other words, it really scales the 72 dpi pattern to 288 dpi rather than 300 dpi. You may want to take a similar approach, since you’d only have to work with whole numbers this way.
  466. So, if you want to do 4-times pattern stretching, you must scale the pattern yourself. If you copy the original pattern into an area that’s twice as wide and twice as tall and use that, you should be all set. You’ll need to use PrGeneral to set the printer to the appropriate resolution and Copybits to copy the pattern into the object that needs to be filled, using the “cookie cutter” approach to fill the object.
  467. X-Ref:
  468. Inside Macintosh Volume I, page I-150
  469. Where CopyBits looks for memory to use
  470. Written:    1/3/92
  471. Last reviewed:    1/27/92
  472. Where does CopyBits look for the memory it needs?
  473. ___
  474. CopyBits checks the stack to determine if there is enough stack space for it to copy the whole image, which in some cases may be roughly up to 5 extra rowbytes of special effects per row, depending on what special effects such as dithering or scaling are being used. If there is not enough stack space for the whole image, CopyBits then tries for half the image, and keeps halving until it gets down to one row of the image (plus the room for the special effects rows). If there is not enough stack space for one row of the image, then CopyBits tries to allocate temporary memory.
  475. Before allocating temporary memory, CopyBits checks if the temporary memory traps are available. (They are available under both System 6 MultiFinder and System 7.) If the traps are available, CopyBits tries to allocate a 256K byte buffer for use as a “fake” stack. (CopyBits used to try for a 64K block, but this has been changed, and it may change again.) If this succeeds, then all is well and the image is copied. If the temporary memory traps do not exist, or if CopyBits cannot allocate a 256K buffer, then the image is not copied and CopyBits returns.
  476. CopyBits does not check in the application heap for free memory, at least not for its work buffer. For its work buffer it will only use the stack, and after that it resorts to temporary memory, if available. There are some circumstances that may cause memory allocations in the application heap, but this memory is not used for CopyBits’s image buffer.
  477. Also, please note that the implementation of CopyBits is subject to change in future versions of QuickDraw.
  478. PICTs with PostScript PICT comments and memory use
  479. Written:    1/10/92
  480. Last reviewed:    2/17/92
  481. Why does my PICT (including dotted lines) use so much memory when drawn in MacDraw, and even more when drawn in SuperPaint? Do they include PicComments for PostScript?
  482. ___
  483. Your guess that it has to do with PicComments is quite right; both MacDraw and SuperPaint include a PostScript representation of the dotted (dashed) lines and some other graphic operations in the PICT, together with the QuickDraw commands. During printing, this allows the LaserWriter driver to take advantage of specific PostScript capabilities that are unavailable in QuickDraw, like primitives for dashed lines.
  484. On the other hand, the PostScript representation for dashed lines is much shorter than the QuickDraw representation, which requires a (long, very long …) sequence of “ShortLine” opcodes. So, another piece of explanation for the large PICT size basically is that QuickDraw does not have facilities to describe dotted lines in an economic way.
  485. SuperPaint also includes a copy of a proprietary dictionary, which adds substantially to the size of a PICT. On the other hand, the code that resides in that dictionary makes the picture’s PostScript representation that much better. Ultimately, WYSIWYG is the goal, and sometimes it takes a little extra code to make that happen. (Incidentally, the PostScript dictionary contained in pictures created by older versions of SuperPaint makes assumptions about the contents of the LaserPrep file which are not true for the recent versions of the LaserWriter driver. Documents containing such pictures will not print correctly any more.)
  486. To determine the primitives that define other nonstandard QuickDraw objects found in drawing applications, you can use MPW’s DeRez function or a third-party utility such as Palomar Software’s PICT Detective on the resource PICT. These tools will provide the opcodes that define the PICT.
  487. Inside Macintosh Vol. V PICT opcode size should be fixed
  488. Written:    1/22/92
  489. Last reviewed:    2/28/92
  490. The definition of PICT version 2 on pages 92-105 of Inside Macintosh Volume V says that the data size of the opcodes $001A and $001B is variable, but also that the data is an RGBColor. This is confusing, since the size of an RGBColor is fixed at six bytes. How can these two opcodes vary in the amount of associated data?
  491. ___
  492. Seems like you’ve run into a cut/paste problem. All the opcodes that refer to table 4 are new for Color QuickDraw. Also, most of them are variable in length, so the author simply had a standard notation for anything that was explained further in table 4 (page V-103). The information contained in table 4 is, in fact, accurate. The size information of several of the opcodes listed is not variable even though the preceding pages told you they were.
  493. All you gotta do is believe table 4 and you will be fine.
  494. Code for filling an area fully bounded by polygon
  495. Written:    2/21/92
  496. Last reviewed:    6/11/92
  497. Currently, when a polygon is filled, an even-odd rule is applied to determine which areas of the polygon are to be filled. For our application, we also need to fill all the areas of the defined polygon. Is there a relatively easy way to accomplish this?
  498. ___
  499. There are many different ways to fill polygons, as you may know. If you do not want to use QuickDraw’s standard FillPoly routine, you’ll have to create your own. The following sample illustrates one technique that might be used to fill the area fully bounded by a polygon. It can be dropped right into the traffic light sample (sample.p) that ships with MPW as a replacement for its DrawWindow procedure. The green star is drawn using FillPoly and the black star is drawn using my filling technique that uses an offscreen bitmap and calcMask to fill in the poly the desired way, then CopyBits to transfer it to the onscreen port. The drawbacks of this method are that it is not as fast as writing a specialized poly routine; the benefits are that it’s small, fast enough for most operations, and can be used for more than just polygons.
  500. {$S Main}
  501. PROCEDURE DrawWindow(window: WindowPtr);
  502. var        MyPoly:PolyHandle;
  503.         MyRgn :RgnHandle;
  504.         OffPort,OnPort:GrafPtr;
  505.     Function    CreateOffport(VAR newOffscreen:grafPtr; 
  506. inBounds:Rect):Boolean;
  507.     var    SavePort,NewPort:Grafptr;
  508.     begin
  509.         GetPort(SavePort);
  510.         NewPort:=GrafPtr(NewPtr(sizeof(grafport)));
  511.         If MemError<>noErr then Begin
  512.             CreateOffport:=false;
  513.             EXIT(CreateOffport);
  514.         END;
  515.        
  516.         OpenPort(newPort);
  517.         With newPort^ do begin
  518.             portRect :=Inbounds;
  519.             RectRgn(ClipRgn,inBounds);
  520.             RectRgn(visRgn, inBounds);
  521.         End;
  522.        
  523.         With newPort^.PortBits DO BEGIN
  524.             Bounds:=Inbounds;
  525.             rowBytes:= ((inBounds.right-inBounds.Left+15) DIV 16) *2;
  526.             baseAddr:= NewPtr(rowBytes 
  527.                             * LONGINT(inBounds.Bottom-inBounds.Top));
  528.         End;
  529.         If MemError <>noErr THEN BEGIN
  530.             SetPort(SavePort);
  531.             ClosePort(newPort);
  532.             DisposPtr(ptr(newPort));
  533.             CreateOffport:=false;
  534.           END
  535.         ELSE  BEGIN
  536.             EraseRect(inBounds);
  537.             newOffscreen :=newPort;
  538.             setPort(SavePort);
  539.             CreateOffPort:=true;
  540.         end;
  541.     end;
  542.    
  543.     Procedure    KillOffPort(oldOffscreen :GrafPtr);
  544.     Begin
  545.         ClosePort(oldOffscreen);
  546.         DisposPtr(OldOffscreen^.portBits.baseAddr);
  547.         DisposPtr(ptr(OldOffScreen));
  548.     End;
  549. BEGIN
  550.     If NOT (CreateOffPort(offPort,window^.portRect)) THEN Exit(DrawWindow);
  551.     If NOT (CreateOffPort(onPort,window^.portRect)) THEN Exit(DrawWindow);
  552.    
  553.     SetPort(window);
  554.     MyRgn:=NewRgn;
  555.     OpenRgn;
  556.         MoveTo(10,25);
  557.         Lineto(70,25);
  558.         Lineto(15,70);
  559.         Lineto(40,10);
  560.         Lineto(65,70);
  561.         Lineto(10,25);
  562.     CloseRgn(MyRgn);
  563.     MyPoly:=OpenPoly;
  564.         MoveTo(10,25);
  565.         Lineto(70,25);
  566.         Lineto(15,70);
  567.         Lineto(40,10);
  568.         Lineto(65,70);
  569.         Lineto(10,25);
  570.     ClosePoly;
  571.     OffsetPoly(MyPoly,0,100);
  572.     SetPort(OffPort);
  573.     FramePoly(MyPoly);
  574.     { Now "Fill the poly" the right way }
  575.     CalcMask(    Offport^.portBits.BaseAddr,OnPort^.portBits.BaseAddr,
  576.                 OffPort^.portBits.RowBytes, OnPort^.portBits.RowBytes,
  577.                 OffPort^.portRect.bottom-OnPort^.portRect.Top,
  578.                 OffPort^.portBits.RowBytes DIV 2);
  579.     SetPort(OnPort);
  580.     SetPort(Window); 
  581.     If gStopped then
  582.         CopyBits(    OnPort^.portBits, Window^.portBits,
  583.                     OnPort^.portRect, Window^.portRect, srcCopy, NIL)
  584.     ELSE
  585.         CopyBits(    OffPort^.portBits, Window^.portBits,
  586.                     OffPort^.portRect, Window^.portRect, srcCopy, NIL);
  587.     IF gStopped THEN
  588.       begin
  589.         ForeColor(greenColor);
  590.         FrameRgn(MyRgn);
  591.       end
  592.     ELSE
  593.       begin
  594.         ForeColor(greenColor);
  595.         PaintRgn(MyRgn);
  596.       end;
  597.     ForeColor(blackColor);
  598.     DisposeRgn(MyRgn);
  599.     KillPoly(MyPoly);
  600.     KillOffPort(Offport);
  601.     KillOffPort(OnPort);
  602. END; {DrawWindow}
  603. Use crsrNew flag to unobscure cursor without mouse move
  604. Written:    3/3/92
  605. Last reviewed:    6/11/92
  606. The Macintosh QuickDraw routine ObscureCursor hides the cursor until the next time the mouse is moved but isn’t affected by HideCursor or ShowCursor. Our application needs to use ObscureCursor while the user is typing but needs the cursor to be visible after no typing has occurred for a short period. How do we “undo” ObscureCursor, since we can’t rely on the user moving the mouse?
  607. ___
  608. The only way to unobscure the cursor is to convince the system that the mouse has moved again. There is no real good way to do this via tool calls, so you are going to have to do it the hard way and simply update the low-memory cursor information to tell the system the cursor moved (even though you do not need to update the actual position).
  609. To tell the system the cursor has changed location, you simply set the crsrNew flag to 1; crsrNew is a byte located at $08CE. When the system sees this byte is 1 it will assume the cursor has moved, unobscure it, redraw at the appropriate place (where it was all along...) and reset crsrNew waiting for the mouse to move again, as in the following C and Pascal examples:
  610. /* the C version... */
  611. void UnObscureCursor ( void )
  612. {
  613.    *(char *)0x8CE = 1;
  614. }
  615. (* the pascal version *)
  616. Procedure UnObscureCursor;
  617. begin
  618.    ptr($08CE)^:=1;
  619. end;
  620. This will do what you want in a short, easy-to-use package.
  621. Macintosh QuickDraw region quirks
  622. Written:    1/1/90
  623. Last reviewed:    11/21/90
  624. I’m working with regions, and I’m having problems with Macintosh QuickDraw trashing the heap and crashing, even though my regions are under 32K.
  625. ___
  626. There are some quirks in the current version of QuickDraw. Here are some the commonly-encountered problems:
  627. 1. When doing operations which use more than one region, sduch as UnionRgn, DiffRgn, XorRgn, or SectRgn, the sum of the sizes of the source regions must be less than 32K, regardless of the size of the resulting region.
  628. 2. FrameRgn will fail if it tries to frame a region bigger than 16K.
  629. 3. If CloseRgn fails, the internal region data is already corrupt; there is nothing you can do to recover. CloseRgn will also fail if there isn’t at least a 32K block of free space available.
  630. Here are some workarounds:
  631. 1. Keep regions small and not too complex. Keep track of the sizes of all regions so you can check the SUM of the sizes before calling a routine that has a 32K limit.
  632. 2. Keep 32K free, or allocate a 32K block and release it just before calling CloseRgn.
  633. Apple is working on these problems and expects to fix them in future versions of QuickDraw.
  634. How to get Macintosh QuickDraw arc endpoints
  635. Written:    1/1/90
  636. Last reviewed:    11/21/90
  637. Is there a way to obtain the endpoints of an arc drawn by the Macintosh QuickDraw arc routines, such as FrameArc and PaintArc?
  638. ___
  639. Given a rectangle R which frames the arc you wish to draw, convert your angles to an absolute coordinate system, where three o’clock is 0 degrees and 12 o’clock is 90 degrees.
  640. Now, let:
  641.     x = .5 (+ or -) (R.right - R.left)
  642.     y = .5 (+ or -) (R.bottom - R.top)
  643. The endpoint of the curve will be defined by:
  644.     EndPoint.h = x (+ or -) cos(ang);
  645.     EndPoint.v = y (+ or -) sin(ang);
  646. h & v are relative to center of rectangle R
  647. This calculates only the upper endpoint of the arc, but you can easily calculate the other endpoint using the same formula by calculating the absolute angle for the start point and applying the same formula.
  648. Here is a subroutine which illustrates the algorithm, in LightSpeed Pascal:
  649. { DrawCurve: draw an arc from 0 degrees until the point defined }
  650. { by 'angle'. At that point draw a 4 by 4 crosshair. }                        
  651. procedure DrawCurve (frame : Rect; angle : integer);
  652. var
  653.   x, y : integer;
  654.   xr, yr : extended;
  655.   rad : extended;
  656. begin
  657.   { Convert angle to radians }
  658.   rad := (90 - angle) / 180 * 3.14159;
  659.   { Find end point }
  660.   xr := (frame.right - frame.left) * cos(rad) / 2;
  661.   yr := (frame.bottom - frame.top) * sin(rad) / 2;
  662.   x := (frame.right + frame.left) / 2 + Num2Integer(xr);
  663.   y := (frame.bottom + frame.top) / 2 + Num2Integer(yr);
  664.   { Draw crosshair }
  665.   MoveTo(x - 4, y);
  666.   LineTo(x + 4, y);
  667.   MoveTo(x, y - 4);
  668.   LineTo(x, y + 4);
  669.   { Draw arc }
  670.   FrameArc(frame, 0, angle);
  671. end;
  672. Macintosh CopyBits no longer limited to 3K
  673. Written:    5/3/89
  674. Last reviewed:    11/21/90
  675. Inside Macintosh Volume I (page 188) says there is a 3K limit for CopyBits. Is this still true?
  676. ___
  677. The CopyBits limit is obsolete; there is no longer a 3K limit. The limit
  678. depends on the amount of RAM in your Macintosh. CopyBits tries to use the stack to do all of the copying. In most cases CopyBits is able to copy entire screen shots at one time. You might run into problems if you don’t have enough stack to hold two times the rowBytes of your source, but even in this case CopyBits will attempt to find the memory it needs.
  679. X-Ref:
  680. Inside Macintosh Volume I, page 188
  681. Why grafPort’s clipRgn should be changed before OpenPicture
  682. Written:    11/1/90
  683. Last reviewed:    12/19/90
  684. On page 189 of Inside Macintosh, Volume I, in the QuickDraw chapter’s description of OpenPicture, is the following warning:
  685. “A grafPort's clipRgn is initialized to an arbitrarily large region. You should always change the clipRgn to a smaller region before calling OpenPicture, or no drawing may occur when you call DrawPicture.”
  686. The “arbitrarily large” clipping region rectangle is set to -32767,- 32767,32767,32767 (top, left, bottom, right) for new ports. This is the largest rectangle possible. If this is not a "valid" clipping rectangle for pictures, what is? Is there some specific limit to the size of the clipping rectangle? Does it depend on either available memory or the size of the picture?
  687. ___
  688. Inside Macintosh ’s warning is based on truth but it’s incomplete. It didn’t actually say that this rectangle is invalid as a clipping region, because this is in fact a perfectly valid clipping region. But, you could run into problems if you use this as a clipping region when creating a QuickDraw picture. It’s not a matter of available memory or size; it’s a simple matter of 16-bit signed integer overflow and underflow.
  689. When you open a picture, the current clip region is recorded in the picture (this wasn’t necessarily true in some early versions of QuickDraw). When you draw the resulting picture using the picture’s picFrame as the destination rectangle, there won’t be any problems. But if you use a destination rectangle that’s larger than the picFrame, QuickDraw scales everything in the picture proportionately, including the clip region. If you allowed the default clip region to be recorded into the picture, then its rgnBBox, already as large as possible, will be made even larger. That means that the -32767 coordinates might wrap around to the positive number range, and the 32767 coordinates might wrap around to the negative number range. This leaves you with an empty clip region. Nothing at all gets drawn when the current port’s clip region is empty.
  690. If the destination rectangle is smaller than the picture’s picFrame, you won’t have any problems because the default clip region will be made smaller, and that’s no problem.
  691. This is why Inside Macintosh suggests that you make the clip region smaller than the default clip region before opening a picture. By doing this, you’re almost guaranteed that the clip region won’t get scaled to the point that it turns inside out. What size should you make it? Small enough so that the risk of the clip region’s coordinates being scaled out of QuickDraw coordinate space is minimal. I usually just set the clip region to the picFrame of the picture. It’s hard to go wrong this way.
  692. Macintosh CalcMask and CopyMask code sample
  693. Written:    2/27/92
  694. Last reviewed:    5/21/92
  695. I can’t get the black-and-white version of my lasso-type tool to work correctly with CalcMask and CopyMask. With CalcCMask it seems to work fine. What could I be doing wrong?
  696. ___
  697. CalcMask and CalcCMask are similar in that they both generate a 1-bit mask given a source bitmap. With CalcCMask, though, a pixMap can be used in place of the source bitmap; the seedRGB determines which color sets the bits in the mask image. An easy mistake to make is to forget that CalcCMask accepts a pointer to a bitmap data structure while CalcMask expects a pointer to the actual bit image. And unlike CalcCMask, which uses bounding Rects for the image’s dimensions, CalcMask uses the bitmap’s rowBytes and pixel image offsets to determine the bounding Rects for the image. A typical call to these routines would be
  698.     BitMap source, mask;
  699.     CalcMask (source.baseAddr, mask.baseAddr, source.rowBytes, 
  700.               mask.rowBytes, source.bounds.bottom-source.bounds.top, 
  701.               source.rowBytes>>1);
  702.     CalcCMask (&source, &mask, &(*source).bounds, &(*mask).bounds, 
  703.                &seedRGB, nil, 0);
  704. One last thing to note when using CalcMask is that the width of the image is in words and not bytes. To learn more about these routines, see page 24 of Inside Macintosh Volume IV and page 72 of Inside Macintosh Volume V. Also, the Developer CD Series disc contains a sample, CalcCMask&CalcMask, that shows how to use both these routines.
  705. Macintosh QuickDraw LineTo bug and workaround
  706. Written:    4/23/92
  707. Last reviewed:    7/13/92
  708. Our zooming function crashes into flames when we pass valid coordinate values to LineTo, as in the following example:
  709.     SetPort(myPort);
  710.     MoveTo(154,31619);
  711.     LineTo(74, -31742); (* You are dead! *)
  712. What can we do to avoid LineTo crashes like this?
  713. ___
  714. The QuickDraw Engineering group is aware of the problem you described. The bug probably is going to be fixed in the next release that includes bug fixes. Given that waiting for a system solution may demand more patience than is reasonable, you may want to consider including in your software some form of workaround that will prevent your users from crashing every time an operation takes the software to the limits of QuickDraw.
  715. One way to approach this problem is to replace the lineProc bottleneck. All you need to do is to check the distance between the current pen position and the line’s end, and when the distance becomes too big (let’s say more than 32000) your procedure will call StdLine a couple of times, splitting the operation in two.
  716. Replacing the bottlenecks is a very straightforward operation (which you are probably already using) and in most of the cases will only result in another level of indirection into StdLine but that will prevent your program from calling QuickDraw with parameters that are guaranteed to cause crashes.
  717. QuickDraw globals at INIT time
  718. Written:    6/1/92
  719. Last reviewed:    9/15/92
  720. If I call InitGraf before I reference CurrentA5, will CurrentA5 be valid and can the QuickDraw globals be referenced off it? The screenBits bounds values seem screwy on some machines. Does the problem lie with CurrentA5? Should I be referencing A5?
  721. ___
  722. Here’s the process used by ShowINIT, which is remarkably compatible with system software and other INITs (and it had better be, because it’s used by more than half the system extensions available):
  723. 1. It saves the value in the CurrentA5 global to restore it later.
  724. 2. It points the A5 register at 4 bytes of storage for use by the system.
  725. 3. It copies the value now in A5 into the CurrentA5 global.
  726. 4. It calls InitGraf, passing a pointer to the thePort field of a QuickDraw globals structure.
  727. 5. It opens a port and draws as necessary. [This is where all the functionality goes.]
  728. 6. After it’s done, it closes its port.
  729. 7. It copies the value saved in step (1) into the A5 register.
  730. 8. It copies the restored A5 value into the CurrentA5 global.
  731. To summarize, ShowINIT saves the A5, creates and initializes its own A5 world, does its drawing, then restores the previous A5 world. For more information on this subject, see the Macintosh Technical Note “Stand-Alone Code.”
  732. So Many Bitmaps, So Little Time
  733. Imaging    M.IM.BitMatToRegion
  734. Revised by:    Rich Collyer    December 1989
  735. Written by:    Rick Blair    April 1988
  736. This Technical Note discusses the routine BitMapToRegion, which converts a bitmap to a region, and is available in the 32-Bit QuickDraw INIT and from Apple Software Licensing.
  737. Changes since October 1989:  Added trap definitions for developers using the 32-Bit QuickDraw version of this routine without the correct MPW include file.
  738. The following routine is now available to convert a bitmap to a region:
  739. FUNCTION BitMapToRegion(region:RgnHandle; bMap:BitMap): OSErr;
  740. in C:
  741. pascal OSErr BitMapToRegion(RgnHandle region, BitMap bMap);
  742. If you are using the 32-Bit QuickDraw version of this routine without the correct MPW include file, then you need to include one of the following definitions:
  743. Pascal
  744. FUNCTION BitMapToRegion (region: RgnHandle; bMap: BitMap): OSErr;
  745.          INLINE $A8D7;
  746. C
  747. pascal OSErr BitMapToRegion (RgnHandle region, const BitMap *bMap)
  748.              = 0xA8D7;
  749. Assembly
  750. _BitMapToRegion        OPWORD        $A8D7
  751. The region will be built so that all one bits in bMap are inside the region and all zero bits are outside of it.
  752. As with all QuickDraw calls which change a region, BitMapToRegion requires you to pass an existing region (originally created by _NewRgn).  If the region cannot be built due to an insufficient heap space or a size greater than 32K, then the routine will return an appropriate error code and the region will be empty.  If the region would have exceeded 32K, the error will be rgnTooBigErr (-500).
  753. This function is useful for a number of situations where you have (or can produce) a bitmap representing an area.  You can use _CalcMask to produce such a bitmap.  Once you have a region, you can perform region operations (i.e., _PtInRgn, _UnionRgn, or _InsetRgn) or call _DragGrayRgn, for example.
  754. This call is part of the 32-Bit QuickDraw INIT ($A8D7).  If you do not wish to depend on 32-Bit QuickDraw, then you can obtain a version of BitMapToRegion in MPW object format which can be linked into an MPW program, by contacting Apple Software Licensing:
  755.             Apple Software Licensing
  756.             Apple Computer, Inc.,
  757.             20525 Mariani Avenue, M/S 38-I
  758.             Cupertino, CA, 95014
  759.             (408) 974-4667
  760.             AppleLink:  SW.LICENSE
  761. If you licensed the older version of this routine, BitMapRgn, contact Software Licensing about receiving an updated version.  We recommend you update your application to use the new version as soon as possible.
  762. The new version is now named BitMapToRegion to be consistent with the version in 32-Bit QuickDraw and the MPW interfaces.  In addition, BitMapToRegion offers new features.  You can now pass a one-bit pixelmap which has been coerced to a bitmap.  If you pass a pixelmap which is too large, then you will get a pixmapTooDeepErr (-148) error.  You can also pass the portBits of a window, much like you would do with a call to _CopyBits.
  763. There is a potential problem with this routine, since MPW 3.1 include files contain information about 32-Bit QuickDraw.  If you want BitMapToRegion to be available on all machines, then you must use the object file from Software Licensing.  The problem is that when you compile your application with MPW 3.1 or later, the 32-Bit QuickDraw version gets preference over the object file.  You must comment out the routine in the include files if you want to use the object file.  If you only care about using BitMapToRegion on machines running 32-Bit QuickDraw, then you need not do anything.
  764. A Leading Cause of Color Cursor Cursing
  765. Imaging    M.IM.ColorCursor
  766. Revised by:    Alan Mimms    October 1989
  767. Written by:    Alan Mimms    June 1989
  768. Working with color cursors you create from scratch can cause headaches.  This Technical Note may help a bit.
  769. Changes since June 1989:  Added a warning about purgeable 'clut' resources.
  770. If you’re building an application that creates color cursors, you may encounter some quirks present in Color QuickDraw that manifest themselves in hard-to-understand ways.
  771. If your cursor is, say, 15 pixels tall and 9 pixels wide, you might be tempted to use these values for the bounds.bottom and bounds.right, respectively, in your cursor’s pixel map.  Don’t.  The problem is that when the cursor’s image needs to be expanded (i.e., when you specify a two bit-per-pixel cursor and the mouse pointer is on an eight-bit screen) the _SetCCursor trap rounds the width of the pixel map in such a way that you’ll get only the space required for a 15 by 8 pixel map allocated for the expanded cursor data.  When the cursor’s image is expanded into this too-small expanded cursor data handle as a 15 by 9 pixel map, something in your heap will get munched.
  772. The cure is simple.  Make certain that you always specify that the pixmapHandle^^.bounds be 16 by 16.  This will cause _SetCCursor to properly allocate the expanded data area, and all will be well in the land.  Since the amount of data drawn for a cursor is specified by the cursor’s pixel values and 'clut' resource, trying to save a few bytes by making the bounds rectangle smaller than 16 by 16 wouldn’t have been very helpful anyway.
  773. Another potential problem is with the color cursor’s color table.  If you load the color table from a 'clut' resource using _GetCTable, you should make sure that the 'clut' is marked non-purgeable while the color cursor is in use.  If you do not take this precaution, bombs will occur if your 'clut' gets purged at in inopportune time.
  774. Color Manager Q&As
  775. Imaging    M.IM.ColorMgr.Q&As
  776. Revised by:    Developer Support Center    October 1992
  777. Written by:    Developer Support Center    October 1990
  778. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  779. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  780. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  781. Color Manager search and complement procedures
  782. Written:    10/7/91
  783. Last reviewed:    11/6/91
  784. The AddComp complement procedure description in Inside Macintosh Volume V, pages 145-147, is vague. The last paragraph on page V-146 states, “Complement procedures work the same as search procedures,” but SearchProc is a function, CompProc is a procedure, and each have a different number of parameters. What else does CompProc need as input and on exit?
  785. ___
  786. CompProc should be declared as a Pascal FUNCTION that returns a Boolean. The code performs a CLR.B for the return value of CompProc, so treat it like SearchProc. CompProc only uses one parameter since its one parameter is a VAR, which means it will be replaced with the correct complementary color. SearchProc returns an index in its second parameter, which is why it needs a second parameter.
  787. Using ResEdit to get Apple icon RGB values
  788. Written:    1/7/92
  789. Last reviewed:    8/1/92
  790. I am trying to find the RGB values for Apple's standard icon colors. I can’t find this information in any documentation. Is this information available?
  791. ___
  792. While the RGB values for the standard Apple icon colors (and other standard palette colors) are not explicitly documented, they are easy to obtain with ResEdit 2.1.1. In any resource file, create and open a new 'pltt' resource. Choose Load Colors from the pltt menu and pick Apple Icon Colors, and a standard palette will be created. Selecting a color will reveal its component values.
  793. ResEdit 2.1.1 is available on the latest Developer CD Series disc and from APDA.
  794. Macintosh Color Manager versus Palette Manager
  795. Written:    1/1/90
  796. Last reviewed:    8/1/92
  797. When should the Macintosh Color Manager be used and when should the Palette Manager be used?
  798. ___
  799. The Palette Manager is by far the friendlier and more versatile of the two if your application uses different colors than the default system colors. It provides all the functionality you need to customize and animate the colors in your application. You shouldn’t ever need to use the Color Manager unless you require custom color search and complement functions. When using the Palette Manager, applications will maintain their respective color environments safely as they move back and forth from foreground to background, and from one screen to another. Accomplishing this with the Color Manager calls is not worth the effort or very safe. For additional information, see the Palette Manager chapter in Inside Macintosh Volumes V and VI.
  800. Color QuickDraw Q&As
  801. Imaging    M.IM.ColorQD.Q&As
  802. Revised by:    Developer Support Center    December 1992
  803. Written by:    Developer Support Center    October 1990
  804. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  805. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  806. New Q&As this month:
  807. Disabling Macintosh Color QuickDraw for testing
  808. Disabling Macintosh Color QuickDraw for testing
  809. Date written:    9/14/92
  810. Last reviewed:    11/1/92
  811. Is there an easy way to disable Color QuickDraw on a Macintosh? I want to do this for testing our application, to make sure it works correctly on a machine without Color QuickDraw.
  812. ___
  813. There’s no easy, or perhaps even hard way to disable features built into the system software your particular machine requires. It’s designed to work well, not to be toggle-able.
  814. Even the hard way isn’t a sure thing—trying to patch out all the Color QuickDraw traps could confuse the rest of the system software, which internally may use undocumented routines to accomplish its tasks.
  815. The easiest way to test on non-Color QuickDraw machines is to get one. Fortunately, the machines without Color QD are the lowest end of the Macintosh price spectrum—such as the Macintosh Classic, PowerBook 100, and Macintosh SE. You can probably rent or borrow one of these if the prices don’t fit your current budget.
  816. Using a Macintosh PICT file that’s larger than available memory
  817. Written:    6/18/90
  818. Last reviewed:    9/24/91
  819. How can I read a 2 MB PICT file into only 1 MB of memory?
  820. ___
  821. You can’t read it in since you don’t have enough memory, but drawing the picture contained in the file using a technique called “spooling” increases your chances of using a 2 MB PICT file with 1 MB memory. Spooling is documented in the Color QuickDraw chapter of Inside Macintosh Volume V (pages 88–89).
  822. Getting a single scan line from a PICT file
  823. Written:    6/18/90
  824. Last reviewed:    9/24/91
  825. Is there any way to obtain a particular scan line from a PICT file?
  826. ___
  827. A PICT file may contain more than just pixmaps, so getting one scan line out of it is not possible. The file may also contain other elements that overlap, such as rects and arcs. The only way to obtain a single line is to draw it off-screen and then, once the whole image is in memory, you can go and study individual pixels.
  828. Determining pixel depth from PICT files
  829. Written:    6/20/90
  830. Last reviewed:    9/17/91
  831. How do you find out the pixel size of a PICT file on the disk?
  832. ___
  833. A picture is by nature independent of depth. For example, you can have a picture containing DrawRects and LineTos and therefore lacking any info regarding depth.
  834. On the other hand, if the picture you are looking at has pixmap opcodes in it, then each pixmap contains its own pixel size and in this case a picture can have a number of depths associated with it.
  835. If you want to see the pixel size for each pixmap opcode in a picture, replace all the bottleneck routines and every time the bitsProc is called you can see the pixmap and get the info out. Since the picture is in a file, you can use the spooling technique described in the QuickDraw chapter in Inside Macintosh Volume V. Be ready to deal with multiple, possibly different, pixmaps as well as direct pixmaps if the picture was created under 32-bit QuickDraw.
  836. ”KnowsPICT,” on the Developer CD Series disc, extracts this kind of information. The System 7.0 Picture Utilities package gets this information too.
  837. Direct RGB PICT file compression
  838. Written:    10/24/90
  839. Last reviewed:    2/14/91
  840. How are bits packed in direct RGB PICT files created by 32-Bit QuickDraw? I looked at the Macintosh Technical Note “Things You Wanted to Know About _PackBits…”, but this run-length encoded compression is clearly inefficient for cases where pixelSize is greater than 8 bits. I write software for machines other than Macintosh that decodes PICT files; therefore, I cannot issue any QuickDraw calls such as _unpackBits.
  841. ___
  842. You’re quite right; compressing direct pixels using straight run-length encoding doesn’t work very well. Fortunately, direct pixel maps aren’t compressed this way. Compression schemes are discussed in Inside Macintosh Volume VI in the section titled “The New OpCodes: Expanded Format.”
  843. In short, if the packType field holds the value 1, then no compression is done at all. The complete pixel image is saved in the PICT. If the packType field holds the value 2 and the pixel map is 32-bits per pixel, then all that’s done is that the alpha-channel byte is removed. So this:
  844.                        00 FF FF FF  00 FF FF FF
  845. is compressed to:
  846.                        FF FF FF  FF FF FF
  847. If the packType field holds the value 3 and the pixel map is 16 bits per pixel, then run-length encoding is done, but not through PackBits. Instead, a run-length encoding algorithm private to QuickDraw is used. This algorithm is very similar to PackBits, but where PackBits compresses runs of bytes, this routine compresses runs of words. The format of the resulting data is exactly the same as described in the Technical Note “Things You Wanted to Know About _PackBits…”, but you’ll get words instead. To build on the example in this Tech Note, lets say the 16-bit pixel image begins with these pixel values:
  848.     AAAA AAAA AAAA 8080 0000 2A2A AAAA AAAA AAAA AAAA 8080 0000
  849.     2A2A 2222 AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA
  850. After being packed by QuickDraw’s internal compression routine, this becomes:
  851.     FE AAAA
  852.     02 8080 0000 2A2A
  853.     FD AAAA
  854.     03 8080 0000 2A2A 2222
  855.     F7 AAAA
  856. or
  857.     FEAA AA02 8080 0000 2A2A FDAA AA03 8080 0000 2A2A 2222 F7AA AA
  858.     *      *                 *      *                      *
  859. where the asterisks mark the flag-counter bytes. Notice that you can’t assume that the pixel values are word-aligned. PackBits packs data 127 bytes at a time, though it will do this for up to 32,767 total bytes. Similarly, the internal compression routine packs data 127 words at a time.
  860. If the packType field holds the value 4 and the pixel map is 32-bits per pixel, then run-length encoding via PackBits is done, but only after some preprocessing is done. QuickDraw first rearranges the color components of the pixels so that each color component of every pixel is consecutive. So the following four pixels (the row below the pixel values indicates a = alpha channel, r = red, g = green, b = blue, and the pixel offset):
  861.             00 FF FF FF  00 FF C0 00  00 FF 80 00  00 C0 80 00
  862.             a0 r0 g0 b0  a1 r1 g1 b1  a2 r2 g2 b2  a3 r3 g3 b3
  863. is rearranged to become:
  864.             FF FF FF C0  FF C0 80 80  FF 00 00 00
  865.             r0 r1 r2 r3  g0 g1 g2 g3  b0 b1 b2 b3
  866. The first four bytes are the red components of the four pixels, the next four bytes indicate the green components of the four pixels, and so on. The alpha channel isn’t included unless the cmpCount field contains 4 rather than the normal 3. If cmpCount contains 4, then all the alpha channel bytes are placed before the red bytes. Once this is done, then PackBits is called to compress the rearranged data.
  867. Those are the only four compression schemes (including no compression) that are supported for direct pixel maps in PICTs. As always, reading PICTs yourself puts you in danger of not being able to read PICTs generated by future versions of QuickDraw. For compatibility reasons, these compression algorithms as I’ve described them probably can’t change in the future. It’s possible that new values for packType could be implemented though.
  868. X-Ref:
  869. Macintosh Technical Note “Things You Wanted to Know About _PackBits…”
  870. Saving 32-bit Macintosh PICTs
  871. Written:    10/30/90
  872. Last reviewed:    2/20/91
  873. I am using a packType=4 and have several questions about saving Macintosh 32-bit images in a PICT format:
  874. 1. What are the ramifications of using cmpCount=3 as opposed to cmpCount=4?
  875. 2. How is the pixData actually stored? According to several references, each line is run-length encoded; that is, [byteCount][data]. If rowBytes>250 then byteCount is a word. After looking at several examples, I came to the conclusion that you are actually using PackBits and that the term “run-length” encoded is a misnomer.
  876. ___
  877. 1. The difference between using cmpCount=3 or cmpCount=4 is that in the first case only the R, G, and B values are stored in the picture; in the second case QuickDraw stores in the picture the alpha channel plus R, G, and B. cmpCount=4 can be used when it is important to also save the alpha channel (as when you have some flags stored there).
  878. 2. Unless rowBytes is less than 8, the pixmap is compressed using PackBits, and the length is a word or a byte depending on rowBytes, but it always refers to the number of bytes comprising one scan line. My guess is that “run-length encoding” refers to the fact that pictures have data organized one row at a time.
  879. To show how direct RGB pixmaps are stored inside a picture, I am including the decoding of a picture that I created to show how the different packing schemes change the resulting pixmap opcode data. First I created a direct RGB pixmap and drew three lines into it. The first line is 8 pixels long with a color of {0x1111,0xAAAA, 0x7777}, the third line is 8 pixels of {0xFFFF, 0x3333, 0xBBBB} and the line in between is two pixels of the first color then two pixels of the second color and so on until you make 8 pixels. Then I created a picture made of CopyBits calls copying the same lines but using different packing schemes. Finally I dumped the contents and the result is what you see here. I have put comments I think help make it clear how the packing scheme of choice changes the results.
  880. I recommend that you have the Inside Macintosh Volume V QuickDraw chapter at hand to check the opcodes and data associated with them. If you had Inside Macintosh Volume VI then you wouldn’t need to also check the 32-Bit QuickDraw docs for the direct RGB pixmap opcodes. The Technical Note “Things You Wanted To Know about _PackBits…” gives details on how the packed data is arranged.
  881. 0256 0000 0000 0008 0008                   /* size and rect        */
  882. 0011 02FF 0C00 FFFF FFFF                   /* PICT2 Header         */
  883. 0000 0000 0000 0000 0008
  884. 0000 0008 0000 0000 0000
  885. 001E                                       /* Default hilite       */
  886. 001A FFFF 3333 BBBB                        /* RGB Fore Color       */
  887. 0001 000A 8001 8001 7FFF 7FFF              /* ClipRgn              */
  888. 009A              /* direct pixels opcode; see IM VI QD chapter for details */
  889. 0000 00FF 8020 0000 0000 0003 0008 0000    /* See IM V or VI QuickDraw chapter
  890. */
  891. 0001 0000 0000 0048 0000 0048 0000 0010    /* packType 0001 = no packing */
  892. 0020 0003 0008 0000 0000 006D A7DC 0000
  893. 0000 0000 0000 0003 0008 0000 0000 0003
  894. 0008 0000
  895. 0011 AA77 0011 AA77 0011 AA77 0011 AA77    /* line one xRGB after xRGB */
  896. 0011 AA77 0011 AA77 0011 AA77 0011 AA77
  897. 0011 AA77 0011 AA77 00FF 33BB 00FF 33BB    /* second line same */
  898. 0011 AA77 0011 AA77 00FF 33BB 00FF 33BB
  899. 00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB    /* third line same  */
  900. 00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB
  901. 009A                                       /* same direct pixels opcode   */
  902. 0000 00FF 8020 0000 0000 0003 0008 0000
  903. 0002 0000 0000 0048 0000 0048 0000 0010    /* packType 2 = fourth byte off*/
  904. 0020 0003 0008 0000 0000 006D A7DC 0000
  905. 0000 0000 0000 0003 0008 0003 0000 0006
  906. 0008 0000
  907. 11AA 7711 AA77 11AA 7711 AA77              /* one line of RGB after RGB   */
  908. 11AA 7711 AA77 11AA 7711 AA77              /* compare with previous       */
  909. 11AA 7711 AA77 FF33 BBFF 33BB              /* same here*/
  910. 11AA 7711 AA77 FF33 BBFF 33BB
  911. FF33 BBFF 33BB FF33 BBFF 33BB              /* and here */
  912. FF33 BBFF 33BB FF33 BBFF 33BB
  913. 009A                                       /* bits opcode */
  914. 0000 00FF 8020 0000 0000 0003 0008 0000
  915. 0004 0000 0000 0048 0000 0048 0000 0010    /* packType 4 = pack     */
  916. 0020 0003 0008 0000 0000 006D A7DC 0000    /* componentCount = 3    */
  917. 0000 0000 0000 0003 0008 0006 0000 0009    /* R,G and B separated   */
  918. 0008 0000
  919.                     /* for details on packed data see Tech Note referenced above*/
  920. 06                  /* first line made of 6 bytes including count    */
  921. F9 11F9 AAF9 77     /* -(-7)+1 of 11, -(-7)+1 of AA, and
  922.                                    -(-7)+1 of 77 -> 8 RGB triplets   */
  923. 19                                   /* second row made of $19 bytes */
  924. 1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB
  925.                                            /* $17+1 unpacked values */
  926. 06                                         /* third line same as first      */
  927. F9FF F933 F9BB                             /* repeated R and B and G values */
  928. 009A                                          /* bits opcode again */
  929. 0000 00FF 8020 0000 0000 0003 0008 0000
  930. 0004 0000 0000 0048 0000 0048 0000 0010       /* same packing = 4 but       */
  931. 0020 0004 0008 0000 0000 006D A7DC 0000       /* component count = 4        */
  932. 0000 0000 0000 0003 0008 0009 0000 000C       /* alpha channel, R, G, and B */
  933. 0008 0000
  934. 08                                            /* first line */
  935. F9 00F9 11F9 AAF9 77
  936.                 /* same as before but packing the high byte (00 value) also */
  937. 1B    /* second line first has -(-7)+1 '00' and then the same line as above */
  938. F900 1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB
  939. 08                                            /* third line same as first */
  940. F900 F9FF F933 F9BB
  941. 00FF                                          /* end of PICT */
  942. A section of the code that produces this picture follows:
  943.     RGBColor    oneColor = {0x1111, 0xaaaa, 0x7777},
  944.                 twoColor = {0xffff,0x3333,0xbbbb};
  945.     SetGWorld(GgwPtr, nil);                   /* set the off-screen GWorld */
  946.     if ( LockPixels(GgwPtr -> portPixMap) )
  947.     {
  948.         EraseRect(&(GgwPtr->portRect));
  949.         RGBForeColor(&oneColor);
  950.         MoveTo(0,0);
  951.         LineTo(7,0);
  952.         MoveTo(0,1);
  953.         LineTo(1,1);
  954.         RGBForeColor(&twoColor);
  955.         MoveTo(2,1);
  956.         LineTo(3,1);
  957.         RGBForeColor(&oneColor);
  958.         MoveTo(4,1);
  959.         LineTo(5,1);
  960.         RGBForeColor(&twoColor);
  961.         MoveTo(6,1);
  962.         LineTo(7,1);
  963.         MoveTo(0,2);
  964.         LineTo(7,2);
  965.         SetRect(&localR,0,0,8,3);
  966.         rr = localR;
  967.         p = OpenPicture(&(GgwPtr->portRect));
  968.         /* first no packing */
  969.         (*(GgwPtr -> portPixMap)) -> packType = 1;
  970.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  971.                 &rr,&localR,srcCopy,nil);
  972.         /* second pack 2: remove alpha chanel */
  973.             OffsetRect(&localR,0,3);
  974.         (*(GgwPtr -> portPixMap)) -> packType = 2;
  975.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  976.                 &rr,&localR,srcCopy,nil);
  977.         /* third pack 4: packing component by component */
  978.             OffsetRect(&localR,0,3);
  979.         (*(GgwPtr -> portPixMap)) -> packType = 4;
  980.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  981.                 &rr,&localR,srcCopy,nil);
  982.         /* The last case is pack 4 but storing the alpha channel also */
  983.             OffsetRect(&localR,0,3);
  984.         (*(GgwPtr -> portPixMap)) -> packType = 4;
  985.         (*(GgwPtr -> portPixMap)) -> cmpCount = 4;
  986.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  987.                 &rr,&localR,srcCopy,nil);
  988.         ClosePicture();
  989.     UnlockPixels(GgwPtr -> portPixMap);
  990.     }
  991. X-Ref:
  992. “Color QuickDraw,” Inside Macintosh, Volume V
  993. “Color QuickDraw,” Inside Macintosh, Volume VI
  994. Macintosh Technical Note “Things You Wanted To Know about _PackBits…”
  995. BitMapToRgn for non-Color QuickDraw Macintosh models
  996. Written:    11/9/90
  997. Last reviewed:    2/20/91
  998. Is _BitmapToRegion available on any pre-System 7 non-Color QuickDraw configurations such as the Macintosh Classic, Plus, or SE? If not, is source or a library module available so that I don’t have to take the time and compatibility risk of rolling my own?
  999. ___
  1000. BitMapToRegion works on pre-color Macintosh systems. You can license BitMapToRegion from
  1001.     Software Licensing
  1002.     Apple Computer, Inc.
  1003.     20525 Mariani Ave. MS:38-I
  1004.     Cupertino, CA 95014
  1005.     AppleLink: SW.LICENSE
  1006.     Phone:(408) 974-4667
  1007. Macintosh QuickDraw pixel map stack requirements
  1008. Written:    12/3/90
  1009. Last reviewed:    5/21/91
  1010. What are the guidelines for determining how much of an image CopyBits can copy to a Macintosh pixel map at one time, given a particular set of characteristics for the source map and the destination map and given how much stack space is available? For example, say that we have an 8-bit-deep pixmap to be copied to a 32-bit-deep pixMap using the ditherCopy mode and expanded by a factor of 4, and we have 45K of stack space.
  1011. ___
  1012. CopyBits’ stack requirement depends on the width of each scan line (rowBytes). The rule of thumb is that you need at least as much stack as the rowBytes value in your image (which can be huge with 32-Bit QuickDraw), with the following additional modifiers: Add an additional rowBytes for dithering; add an additional rowBytes for any stretching (source rect != dest rect); add an additional rowBytes for any color map changing; add an additional rowBytes for any color aliasing. The stack space you need is roughly five times the rowBytes of your image. In general, you’re better off processing narrower scan lines. Reducing the vertical size will not affect stack requirements. Narrow, tall bands (if you can use them) will reduce the stack requirements.
  1013. Color and non-Color QuickDraw trap dispatch differences
  1014. Written:    1/28/91
  1015. Last reviewed:    2/13/91
  1016. Why does a call to RGBForeColor cause a corruption of the stack without resulting in an unimplemented trap error on non-Color QuickDraw Macintosh systems?
  1017. ___
  1018. The trap dispatcher on Color QuickDraw and non-Color QuickDraw machines are different. If you look at page 89 of Inside Macintosh Volume I, you’ll see the toolbox trap word format as it was in the days before Color QuickDraw. Bit 9 was “reserved for future use” and was ignored by the trap dispatcher, and so it was normally set to 0. That means that valid toolbox traps could either look like $A8XX or $A9XX as long as the auto-pop bit was turned off. Color QuickDraw machines have a trap dispatcher that uses that reserved bit to allow for more trap words, and therefore it has a much larger trap dispatch table. Color QuickDraw traps have that reserved bit set, so those traps look like $AAXX or $ABXX.
  1019. When a non-Color QuickDraw machine tests to see if a trap is implemented or not, it just checks the trap dispatch table to see if a routine is implemented for that trap or not. Because the reserved bit is ignored, trap words that look like $AAXX are treated as equivalent to $A8XX and trap words that look like $ABXX are treated as equivalent to $A9XX. The trap word for RGBForeColor is $AA14. If you call RGBForeColor on a non-Color QuickDraw machine, $AA14 is treated as $A814, which is the trap word for SetFractEnable. SetFractEnable is implemented on 128K ROM machines or greater, so no unimplemented trap error occurs.
  1020. If you look at recent DTS sample programs, such as the Utilities sample (SC.025.Utilities, which you can find on AppleLink in Developer Support and on the current developer CD), you’ll see a routine in Utilities.c called TrapExists. It takes into account the size of the trap dispatch table so that you can tell in one call whether a routine is implemented or not regardless of whether it’s a Color QuickDraw trap or not and regardless of what kind of Macintosh you’re running on.
  1021. Under system software version 7.0, the trap dispatcher is modified on non-Color QuickDraw machines so that many Color QuickDraw traps are implemented and work as well as they can in black and white.
  1022. Macintosh OpenCPicture 72-dpi calculation bug
  1023. Written:    2/12/91
  1024. Last reviewed:    2/20/91
  1025. The 32-Bit QuickDraw _OpenCPicture call incorrectly calculates the 72-dpi frame width if the height of the native resolution srcRect exceeds 910 dots. To work around this problem, I calculate the 72-dpi frame independently, and store it in the PicHandle returned by _OpenCPicture.
  1026. ___
  1027. It’s a known bug that under Macintosh system software versions 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2, OpenCPicture doesn’t properly calculate the right coordinate of the 72-dpi picFrame if the height of the srcRect (native resolution rectangle) multiplied by 72 exceeds $0000FFFF. That works out to a maximum height of 910 pixels, just as you found. This bug is fixed in System 7.0, but gestaltQuickdrawVersion returns $0220 both under system software versions 6.0.5 and 7.0, so you can’t tell whether the bug is fixed that way. Instead, you should use Gestalt with the gestaltSystemVersion selector. If the returned value is $0700 or greater, then let OpenCPicture handle the picFrame calculation; otherwise you should do the calculation yourself.
  1028. GetGWorldPixMap bug and workaround
  1029. Written:    3/12/91
  1030. Last reviewed:    10/9/91
  1031. Why does GetGWorldPixMap (when called on a Macintosh II, IIcx, or IIx running system software version 6.0.5 or 6.0.7 with 32-Bit QuickDraw 1.2) return a combination of the device field (two bytes) and the first two bytes of the portPixMap field? Is this a bug?
  1032. ___
  1033. Your analysis of GetGWorldPixMap is exactly right: It doesn’t work correctly in system software versions 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2. It returns a value that’s two bytes before the value it’s supposed to return.
  1034. The solution is to use GWorldPtr->portPixMap instead of GetGWorldPixMap. It’s safe to do this, but you should use GetGWorldPixMap under System 7. Not only is the bug fixed there, but dereferencing the port is dangerous under System 7 because it may not be CGrafPort. Use Gestalt with the gestaltQuickdrawVersion selector to determine whether you can use GetGWorldPixMap. If Gestalt returns a value from gestalt8BitQD ($0100) through gestalt32BitQD12 ($0220), then GetGWorldPixMap either doesn’t exist or is the buggy version. If it returns gestalt32BitQD13 ($0230) or higher, then GetGWorldPixMap does exist and works correctly. Interestingly, GetGWorldPixMap can be called on a black-and-white QuickDraw machine under System 7. It returns a handle to a structure that should be treated as a bitmap structure, though there are some undocumented fields after the normal bitmap fields. To tell whether GetGWorldPixMap is available on a black-and-white QuickDraw machine, you must check the system software version by calling Gestalt with the gestaltSystemVersion selector. If it returns $0700 or higher, GetGWorldPixMap is available.
  1035. System 7 TextMode problem and workaround
  1036. Written:    6/12/91
  1037. Last reviewed:    8/13/91
  1038. Our application uses the TextMode (blend + mask) as documented in Inside Macintosh Volume V (blend is equal to the current ditherCopy constant) to make translucent text. Under System 7, this transfer mode causes garbage to appear when the text is drawn. Is there a way to work around the problem? Will there be a fix?
  1039. ___
  1040. The problem you are seeing is due to the use of CopyDeepMask instead of the old-fashioned CopyBits to do the job. It is being studied now, and the hope is that it will work as advertised in a future release. One workaround is to render the text to an off-screen pixmap and then call CopyBits (using blendMode) to actually put it in the picture.
  1041. Using dithering and animation on the same Macintosh image
  1042. Written:    6/19/91
  1043. Last reviewed:    10/15/91
  1044. When setting up a dithered grayscale image for subsequent animation (to adjust brightness, for example), a conflict arises between the use of Palette animation and the ditherCopy CopyBits mode. This problem is demonstrated in the develop #5 GiMeDaPalette code sample: If you change srcCopy to ditherCopy in the CopyBits call, then run the program and select Animate, the resulting image is pure black and white, with what appears to be an attempt to dither with just the black-and-white color table entries (that are not reserved for animation).
  1045. This happens because ditherCopy tries to use the inverse table to do color matching, but when the image is animated, the inverse table colors are limited to just black and white.
  1046. To work around the problem, you can jump into the bottlenecks and when you see the PICT hitting the opcode for CopyBits, change the PICT from a srcCopy to a ditherCopy. This way the dithering happens when you do the call to DrawPicture and not later on. This makes it possible to use dithering and animation on the same image.
  1047. Rendering color PICTs in a black-and-white environment
  1048. Written:    7/22/91
  1049. Last reviewed:    9/17/91
  1050. I want to be able to render a color PICT as a black-and-white image substituting patterns for colors. My images are pretty small and have fewer than 16 colors. What do you suggest as the easiest way?
  1051. ___
  1052. One easy way is to take advantage of 32-Bit QuickDraw and System 7.0’s ditherCopy transfer mode modifier or flag (documented in Inside Macintosh Volume VI, page 17-17). Call DrawPicture into an off-screen pixmap with the pixel depth of the original color PICT. Then call CopyBits to copy the pixmap to the screen, with srcCopy + ditherCopy as the transfer mode. This will result in a nicely dithered image on the black-and-white end.
  1053. Under System 6 without 32-Bit QuickDraw, the solution is not nearly so cut and dried. One way might be to take advantage of the fact that DrawPicture goes through the QuickDraw bottlenecks for drawing. For each grafproc in your PICT, you’d intercept StdBits during DrawPicture and call your own dithering routine to examine the foreground color and set the pen pattern or fill pattern so that it has about the same lightness as the original color.
  1054. Well, this came out as a great sales pitch for writing a System 7-savvy app!
  1055. Highlighting ignored if foreground same as background color
  1056. Written:    8/7/91
  1057. Last reviewed:    9/24/91
  1058. Under System 7, but not System 6, HiliteColor is not used for InvertRect when the hilite bit is set and the background is exactly black (R=G=B=$0000). Also, HiliteColor doesn’t draw when a pen mode of XOR is used in a LineTo call.
  1059. ___
  1060. The problem you encounter exists whenever the background and foreground colors are the same when using highlight mode. If the foreground color is the same as the background color, highlighting is ignored. Therefore, when you set the foreground color to white, you should set the background color to something other than the default color of white.
  1061. Gestalt 'qdrw' selector bug and workaround
  1062. Written:    8/1/91
  1063. Last reviewed:    10/9/91
  1064. Why does Gestalt tell me I have Color QuickDraw features on a non-Color QuickDraw machine?
  1065. ___
  1066. The gestaltQuickdrawFeatures ('qdrw') selector, used for determining your system’s Color QuickDraw features, has a bug that causes it to tell you incorrectly that noncolor machines have color. The fix is quite simple: Gestalt has another selector, gestaltQuickdrawVersion ('qd  '), which simply returns the QuickDraw version number. This version number is < gestalt8BitQD for classic QuickDraw and >= gestalt8BitQD for Color QuickDraw (see Inside Macintosh Volume VI, page 3-39, for more information). The trick is to ask Gestalt for the QuickDraw version first; once you’ve determined that you have Color QuickDraw, the 'qdrw' selector is OK to use to find out specifics.
  1067. Version 2 PICTs on pre-Color QuickDraw models
  1068. Written:    8/13/91
  1069. Last reviewed:    10/22/91
  1070. Inside Macintosh Volume V says a System 4.1 (and later) patch ensures that version 2 PICTs are displayed correctly on earlier machines that don’t have Color QuickDraw, such as the Macintosh Plus and SE. However, my version 2 PICT, consisting primarily of a pixmap (opcode = $90 since rowBytes <8) displays correctly on a Macintosh IIfx but displays garbage on a Macintosh SE.
  1071. ___
  1072. The PICT problem you reported is caused by a bug in 6.0.7 QuickDraw. The workaround for the time being is to:
  1073. • Use System 7.0, where it’s been fixed, or
  1074. • Don’t use opcode $90. Instead, use padding so that opcode $98 can be used. (Opcode $98 is the packed CopyBits version that works for rowBytes >= 8.). You can do this by creating the picture with a pixmap that’s wider than you actually need, and then use the clip region to clip out the part you don’t need.
  1075. GetPixelsState is slow sometimes
  1076. Written:    8/27/91
  1077. Last reviewed:    9/24/91
  1078. Why do I sometimes see incredible slowdowns under System 7.0 when calling either GetPixelsState or LockPixels (I’m not sure which) for the PixMapHandle of a GWorld allocated in temporary memory?
  1079. ___
  1080. GetPixelsState takes an arbitrary amount of time since it makes a call to RecoverHandle to get the handle pointing to the baseaddr. Therefore, the slowdown you see as actually due to the call to RecoverHandle, which is slow because it must traverse the heap to find the pointer to the baseaddr. LockPixels is not responsible for the slowdown because it does not make call to any traps that could take an extended amount of time.
  1081. OpenCPicture and PICTs other than 72 dpi
  1082. Written:    10/2/91
  1083. Last reviewed:    10/8/91
  1084. Can I use OpenCPicture to create PICTs with a higher resolution than 72 dots per inch (dpi)?
  1085. __
  1086. There’s good news and bad news: The good news is that you’re on top of the situation, which means the bad news is that there aren’t better ways to do what you want to do, mostly. Here’s the scoop:
  1087. You can use vRes and hRes in pictures opened with OpenCPicture to tell QuickDraw it’s not a 72-dpi picture, and as long as the application that receives the picture uses DrawPicture to image it, QuickDraw will Do The Right Thing—scaling it on the screen to 72 dpi instead of making it humongously large. Unfortunately, this way you lose hairlines; if you print such a picture to a 72-dpi grafPort (like the LaserWriter driver normally returns), you’ll get 1/72-inch lines instead of 1/300-inch lines as you probably want.
  1088. (This can work correctly, but the receiving application has to notice that your picture is bigger than 72 dpi and ask PrGeneral to increase the resolution of the printing grafPort accordingly, and this doesn’t always or often happen.)
  1089. No System 7 QuickDraw alpha channel support
  1090. Written:    10/23/91
  1091. Last reviewed:    11/27/91
  1092. How can I directly access the alpha channel (the unused 8 bits in a 32-bit direct pixel using QuickDraw) under System 7? Under System 6 it was easy, but under System 7’s CopyBits() the alpha channel works with srcXor but not with srcCopy.
  1093. ___
  1094. With the System 7.0 QuickDraw rewrite, all “accidental” support for the unused byte was removed, because QuickDraw is not supposed to operate on the unused byte of each pixel. QuickDraw has never officially supported use of the extra byte for such purposes as an alpha channel. As stated in Inside Macintosh Volume VI, page 17-5, “8 bits in the pixel are not part of any component. These bits are unused: Color QuickDraw sets them to 0 in any image it creates. If presented with a 32-bit image—for example, in the CopyBits procedure—it passes whatever bits are there.”
  1095. Therefore, you cannot rely on any QuickDraw procedure to preserve the contents of the unused byte, which in your case is the alpha channel. In fact, even CopyBits may alter the byte if stretching or dithering is involved in the CopyBits by setting them to zero. Therefore, the only possible workarounds for this problem are to not use the unused byte for alpha channel storage since the integrity of the data cannot be guaranteed; or, to not use QuickDraw drawing routines which can alter the unused byte.
  1096. BitsToRgn and MPW BitMapToRegionGlue
  1097. Written:    10/29/91
  1098. Last reviewed:    12/11/91
  1099. Which version of the system software first contained the call BitsToRgn? Is there a workaround for this call if my users have an earlier version of system software?
  1100. ___
  1101. The call BitmapToRegion was introduced with 32-Bit QuickDraw and became fully documented in Volume VI of Inside Macintosh, which is primarily System 7 information. However, since the differences between System 7’s QuickDraw and 32-Bit QuickDraw are minor, most of System 7’s QuickDraw routines are available in system software prior to System 7.0 using the 32-bit QuickDraw INIT.
  1102. To check to see if a system contains 32-bit QuickDraw, you can use the following snippet of code:
  1103.     /* Find out if GWorlds and CQD are implemented on this machine */
  1104.     (void) Gestalt (gestaltQuickdrawVersion, /*<*/&qdVersion);
  1105.     gHasGWorlds = (qdVersion > gestaltOriginalQD && 
  1106.                    qdVersion < gestalt8BitQD)
  1107.                   || qdVersion >= gestalt32BitQD;
  1108. If you are using MPW as a development platform, MPW has a library call you can use that will allow you to use the routine regardless of whether or not 32-bit QuickDraw exists. The glue routine is called BitMapToRegionGlue() and is available to MPW users. Substitute this call for BitMapToRegion calls and the glue code will take care of patching in the proper code if 32-bit QuickDraw does not exist. If you’re using Think C, you can use the oConv utility to convert the MPW object file into a Think C usable format.
  1109. Ensuring even rowBytes for 'cicn' resources
  1110. Written:    12/4/91
  1111. Last reviewed:    1/27/92
  1112. Is there any way to force bitmaps and masks within a 'cicn' resource to have an even rowBytes (using ResEdit)? I want to avoid duplicating icon bitmaps—one for color systems set to B&W and one for B&W systems—to reduce program size as well as development and maintenance costs. The bitmaps in the 'cicn' can also be sized specifically to the task, whereas the old B&W icons are of a fixed size and contain no sizing information. It’s simple enough to read in a 'cicn' and extract the bitmap. The problem is that on a 68000 (no Color QuickDraw), if rowBytes is odd, an odd address trap results.
  1113. ___
  1114. There isn’t any way to get ResEdit itself to create bitmaps with even rowBytes for 8 x 8 'cicn' resources, but here are few suggestions:
  1115. You could process your 'cicn' resources first, so that they have bitmaps as you require them. To alter the resource with a quick little program would be trivial, especially given that the bitmap data sits last in the 'cicn'. All you’d need to do is expand the bitmap image data by padding each line to an even length and then changing the rowBytes value. Or you could de-rez the 'cicn's and patch them with a text editor, either by hand or with a search-and-replace script of some kind.
  1116. CopyBits blend mode: OpColor’s affect & eliminating banding
  1117. Written:    12/11/91
  1118. Last reviewed:    2/17/92
  1119. I have two gray-colored pixmaps that I wish to blend together; one is on the screen, the other in an off-screen pixmap. I use CopyBits to copy the off-screen to the screen, but it does not seem to blend them. Instead, it seems to match the colors of the screen bitmap to the closest colors in some table, thus having the effect of reducing the number of colors displayed on the screen bitmap. Any suggestions?
  1120. ___
  1121. There are two distinct questions here: 1) Why ain’t it blending? and 2) What’s this banding for? The first problem is almost certainly because OpColor isn’t set properly. This is a third, implicit, operand on several arithmetic graphics operations, including blend. For blend, it describes the proportions to mix the source and destination colors in the blend. For an equal mix, you should set this color to a halfway gray. (Call OpColor() with a color where red, green, and blue all equal $8000.) This effect is described in the description of the blend mode on page 60 of Inside Macintosh Volume V. Unfortunately, the initial value for OpColor is black (0,0,0), so you were seeing no mixing of your off-screen data.
  1122. The second half of your question is why you’re getting a banding effect. (When you fix the above problem, you’ll still get banding.) Unfortunately, the arithmetic modes are constrained by the size of the inverse table. As your screen no doubt uses the default 4-bit inverse table, you’ll find that you’ll get only 2^4 = 16 levels of gray. If you enlarge your screen’s inverse table to 5 bits, the maximum allowable, you’ll still only get 32 gray levels. (To do this, set the gdResPref field in the GDevice to 5, then call MakeITable().) The only way to get a fully-gradual, great-looking effect is to do all the work off-screen in 24-bit deep pixmaps, and then copy it to the screen. Because they can operate directly on colors, rather than having to work through the intermediary of color indices, direct pixmaps are not limited by inverse tables (in fact, they don’t even have real inverse tables). You could use 16-bit pixmaps, but they only provide 32 grays (having only 5 bits for each component), so this wouldn’t be any better than increasing the size of the inverse table.
  1123. Icon dimming under System 7 and System 6
  1124. Written:    1/6/92
  1125. Last reviewed:    2/6/92
  1126. When you bring up the Control Panels window under System 7 on a color system and click a control panel item icon, it paints itself that fancy gray. How can I get that effect?
  1127. ___
  1128. To get the fancy System 7 icon dimming to work in your program, use the icon drawing routines PlotIconID or PlotCIconHandle with an IconTransformType of ttSelected. Both of these routines and their transform types are used by the control panel and are described in the Macintosh Technical Note “Drawing Icons the System 7 Way.”
  1129. If you want the same effect under System 6, you’ll have to emulate the dimming of the icons via QuickDraw, by installing a color search proc to dim the RGB values that the icon uses. On page 146 of Inside Macintosh Volume V is a description of how to define and install your custom search proc.
  1130. QuickDraw out of memory if debugger invoked by “Jackson”
  1131. Written:    3/11/92
  1132. Last reviewed:    4/7/92
  1133. I am getting a strange bug in which the Macintosh debugger is being invoked by an A-trap marked “Jackson” when I call SetCCursor in certain situations and a second monitor is hooked up. The cursor structure being passed appears to be valid. I’ve also been crashing unexpectedly in this same spot for the past few weeks. I assume Jackson is some kind of error assertion that was left in System 7’s Color QuickDraw code. What gives?
  1134. ___
  1135. Jackson was a code name for 32-Bit QuickDraw. The trap you refer to is in fact never called; it’s not supposed to be encountered by you ever. The trap is reserved for Apple to use in future versions of Color QuickDraw. If you examine the code directly preceding the _Debugger, you will notice that it is doing
  1136.         MOVEQ      #$19,D0
  1137.         JSR        ([$1524])
  1138. which for you and me is
  1139.          MoveQ #25,D0                ; say that memory is full…
  1140.         _SysError                    ; and call syserror
  1141. the line following would be...
  1142.         _Debugger ; Hey! sysError came back! Better drop into the debugger
  1143. What’s all this tell you? You have a debugger installed that is rts’ing from the SysError vector (you aren’t supposed to return from SysError normally), or you have installed your own SysError vector which is rts’ing. At any rate, if you examine the code directly following the debugger statement and see what it does, you might imagine the source code looks something like this:
  1144. MemFull       MoveQ #25,D0              ; say that memory is full...
  1145.               _SysError                 ; and call syserror
  1146. ; If it returns better go into the debugger since its not supposed to return
  1147.               _Debugger                 ; Hey! sysError came back!
  1148. ;
  1149. CallNewHand   _NewHandle
  1150.               bne.S  MemFull            ; could not get the memory, just die
  1151.               rts
  1152. What’s happening is that you’re running out of memory somehow (several places call MemFull, not just the above place), so you’d need to use a stack crawl to figure out how you got there. But, the bottom line, QuickDraw has run out of memory and cannot continue; it tried to put up a system error dialog to tell the user and for some reason the machine did not get restarted and the SysError vector returned. You are now in your debugger, since QuickDraw put up the system error dialog because it could not continue.
  1153. ditherCopy not supported on LaserWriter or ImageWriter
  1154. Written:    5/31/91
  1155. Last reviewed:    11/6/91
  1156. ditherCopy is not supported on LaserWriters or ImageWriters. On a LaserWriter, ditherCopy gets misinterpreted and inverts the image. On an ImageWriter it’s treated as a srcCopy. The ImageWriter driver doesn’t support color grafPorts, which is the only way to do the pixel image required for ditherCopy. Use srcCopy instead for both printers.
  1157. Macintosh Color QuickDraw CalcCMask and SeedCFill clarified
  1158. Written:    1/1/90
  1159. Last reviewed:    11/21/90
  1160. I’m having trouble using CalcCMask and SeedCFill. What am I doing wrong?
  1161. ___
  1162. There is some confusion regarding the use of the Macintosh Color QuickDraw routines CalcCMask and SeedCFill, which are analogous to the older CalcMask and SeedFill. Much of the confusion was caused by early documentation errors. Be sure you have the release version of Volume 5 of Inside Macintosh and version 2.0 or later of the MPW interface files.
  1163. The correct interface for CalcCMask is:
  1164. PROCEDURE CalcCMask(srcBits, dstBits: BitMap;
  1165.           srcRect, dstRect: Rect;
  1166.           seedRGB:     RGBColor;
  1167.           matchProc:    ProcPtr;
  1168.           matchData:    LongInt);
  1169. The correct interface for SeedCFill is:
  1170. PROCEDURE SeedCFill(srcBits, dstBits: BitMap;
  1171.           srcRect, dstRect: Rect;
  1172.           seedH, seedV:   INTEGER;
  1173.           matchProc:    Ptr;
  1174.           matchData:    LongInt);
  1175. Each routine calculates a one-bit deep bitmap representing either the mask or the fill area depending upon the routine. In both cases, the source bitmap may be either a bitmap or a pixmap, but the destination must be a bitmap, because it must have a depth of one-bit.
  1176. It is difficult to pass a pixmap for the source parameter because of Pascal’s type checking. To get around this difficulty, you can declare a new type:
  1177.      BitMapPtr  =  ^BitMap
  1178. then use it to coerce the pixmap as follows:
  1179.      SeedCFill(BitMapPtr(@myPixMap)^, ...);
  1180. If you have a PixMapHandle, do the following:
  1181.      SeedCFill(BitMapPtr(myPixMapHandle^)^, ...);
  1182. If you are using a grafPort (or a window), you can pass myWindow^.portBits and not have to worry about whether the port uses a bitmap or a pixmap.
  1183. Most of the other parameters are explained in detail in Inside Macintosh. To use the matchProc and the matchData parameters, though, you need more information.
  1184. As stated in Inside Macintosh, the matchProc parameter is a pointer to a routine that you would like to use as a custom SearchProc. To better understand how this is used, it is helpful to know how SeedCFill and CalcCMask actually work.
  1185. Both routines start by creating a temporary bitmap which, by definition, is one bit deep. The source pixmap (or bitmap) is then copied to the temporary bitmap using CopyBits. This copy causes the image to be converted to a depth of one-bit. Now with a normal black-and-white image, the standard CalcMask or SeedFill routine is used to generate the destination bitmap.
  1186. Most of the real work is done in the original call to CopyBits, which maps the pixmap image to a monochrome bitmap equivalent. For each color in the source pixmap, CopyBits will map it to either black or white. Which colors map to black and which ones to white is determined by the SearchProc.
  1187. SeedCFill installs a default SearchProc that maps all colors to black except for the color of the pixel at (seedH,seedV). SeedFill then calculates as usual the fill mask for the white bits .
  1188. The default SearchProc for CalcCMask maps all colors to white except the color passed in the seedRGB parameter. The seedRGB parameter, then, would be the color of the item that you wanted to “lasso.”
  1189. But suppose you want to fill over all colors that were shades of green, not just the particular shade of green at (seedH,seedV). Or maybe you want to fill over all colors that are lighter than 50 percent brightness. Or maybe you want to use dark colors as edge colors for CalcCMask. To do such things, you need to pass a pointer to your own SearchProc in the matchProc parameter.
  1190. Because your matchProc is just a custom search procedure for the Color Manager, it should be declared as one, but Volumes I–V of Inside Macintosh have documented this routine incorrectly. The correct declaration for a custom SearchProc is as follows:
  1191. FUNCTION SearchProc(VAR RGB: RGBColor;
  1192.           VAR result: LongInt) : Boolean;
  1193. Normally, as each SearchProc is installed, it is added to the head of the SearchProc chain, so that it is called before all of the other ones that were already installed. When a SearchProc is installed, it can do one of three things:
  1194. 1. Completely ignore the call by returning FALSE and not modifying any of the input parameters;
  1195. 2. Completely handle the call by setting the result parameter to be the index into the color table that matches (according to your rules) the RGB parameter. In that case, the SearchProc returns TRUE;
  1196. 3. Partially handle the call by modifying the RGB parameter, then returning FALSE.
  1197. In cases 1 and 3, the Color Manager continues down the SearchProc chain until it finds one that returns TRUE. If none of the custom routines handle the call, then the built-in default routine is used. In case 3, you can change the RGB color that is being matched. For example, if you want all shades of green to map to pure green, modify the RGB color, then return FALSE, letting the Color Manager find the index of that green in the color table.
  1198. In case 2, you return TRUE to indicate that you handled the call, and you return the color table index in the result parameter. The Color Manager then uses that index. For example, if you want to substitute white for all colors that can’t be matched exactly in the color table, then each time you get called you either return the index into the color table of the exact color, or 0 (which is the index for white) for all other colors.
  1199. A custom SearchProc for SeedCFill and CalcCMask should always return TRUE because the default Color Manager SearchProc usually doesn’t make sense. Because SeedCFill and CalcCMask are using CopyBits to copy to a 1-bit bitmap, you need to set the result to be either 0 or 1 (the only possible values in a 1-bit bitmap). A result of 0 is white, and a result of 1 is black.
  1200. All colors for SeedCFill that should be “filled over” would generate a result of 0 (white), and all colors that stop the fill generate a 1 (black). SeedFill is then called to fill the white area. All colors for CalcCMask that you want to form boundaries should generate results of 1 (black).
  1201. When your SearchProc gets called, the gdRefCon field of the current GDevice (theGDevice^^.gdRefCon) contains a pointer to the following record:
  1202.     matchRec  =  RECORD
  1203.       red:       Integer;
  1204.       green:     Integer;
  1205.       blue:      Integer;
  1206.       matchData: LongInt;
  1207.     END;
  1208. The red, green, and blue parameters for SeedCFill are the values of the color of the pixel at (seedH,seedV). For CalcCMask, they are the fields from the seedRGB parameter. Your SearchProc can use this information to decide which colors are “fill-over” colors and which colors are “boundary” colors. For example, if you always set (seedH,seedV) to be the mouse point, your SearchProc then bases its decisions using the color of the pixel under the cursor. For example, the user clicks a shade of green, so all shades of green get filled over.
  1209. The matchData field contains the value that you passed into the SeedCFill or CalcCMask routines in the matchData parameter. The use of this field is completely user-defined. For example, since your SearchProc routine may be a separate module, you might want to use this field to pass a handle to your variables. This field can contain a handle, a pointer, a long integer, or whatever; or you can just ignore this field altogether.
  1210. Warning: There are some features of CalcCMask and SeedCFill you should be aware of. To understand them, you should be familiar with the use of CalcMask and SeedFill, which are described in the QuickDraw chapter of Inside Macintosh Volume IV.
  1211. CalcCMask and SeedCFill both use a parameter set that is very similar to the one used by CopyBits. CalcMask and SeedFill, however, are a different story. Instead of passing bitmaps and rectangles to SeedFill and CalcMask, these routines use an unusual set of parameters that describe the memory to be operated upon in terms of pointers, height, width, and offsets to the next row (rowBytes). Although these parameters are fairly easy to calculate, there are some limitations.
  1212. The most restrictive limitation is that the width of the rectangle used must be an even multiple of 16 bits. This limitation exists because the width of the rectangle is passed to SeedFill and CalcMask as a number of words (2 bytes). When calculating this parameter, SeedCFill and CalcCMask round down to an even word boundary. This rounding means that the rectangles you pass to CalcCMask and SeedCFill should be an even multiple of 16 pixels in width. If they are not, then the rightmost portion of the mask will be garbage.
  1213. To figure out the color of the pixel at (seedH,seedV), SeedCFill calls GetCPixel. GetCPixel finds the color of the pixel at (h,v) in the current port. Therefore, if you pass a pixmap that is not the pixmap of the current port you will get bizarre results. In other words, seedH and seedV are expressed in the local coordinates of the current port, not the coordinate of the source pixmap.
  1214. You have two methods to make it work. First, always pass the pixmap of the current port as the source parameter. If you are using an off-screen pixmap, it is a good idea to have an associated port for it, and then call SetPort, passing it a pointer your off-screen port, before you call SeedCFill.
  1215. The second method involves letting SeedCFill get some wrong value for the color at (seedH,seedV) then using your own custom SearchProc to do the real work. The default SearchProc for SeedCFill relies on getting the correct color, but your SearchProc doesn’t have to.
  1216. SeedCFill also makes the assumption that the seedH and seedV parameters are in the local coordinate system of the destination bitmap. This assumption comes into play when SeedCFill calculates the seedH and seedV parameters for SeedFill.
  1217. All this means that SeedCFill only works correctly if the source pixmap, destination pixmap, and current port all use the same coordinate system. Because of the above problem, this is almost automatic since the current port’s portRect and the bounds of the source pixmap have to be the same anyway.
  1218. The easiest way to make all this work is to have your main port be an even multiple of 16 pixels wide. Then, make sure that your source and destination structures (pixmap or bitmap) are all the same size and all have origins of (0,0).
  1219. System 7.0ß1 BitMapToRgn limitation
  1220. Written:    1/1/90
  1221. Last reviewed:    12/7/90
  1222. BitMapToRegion does not work as described in the Macintosh Tech Note “32-Bit QuickDraw: Version 1.2 Features” for a pixmap with baseAddr = (NuBus address). Which calls support pixmap 32-bit base addressing with pmVersion = 4?
  1223. ___
  1224. As of System 7.0ß1, BitMapToRgn cannot handle a bitmap whose base address is in the NuBus address space or any bitmap that requires 32-bit addressing. The problem will be fixed for System 7’s final release. BitMapToRgn seems to be the only call that doesn’t yet support 32-bit addressed bitmaps.
  1225. X-Ref:
  1226. DTS Macintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  1227. Macintosh Color QuickDraw and packed PICTs
  1228. Written:    1/1/90
  1229. Last reviewed:    12/7/90
  1230. Does Macintosh 32-Bit QuickDraw support packed PICTs? What’s the technique for saving packed PICT formats? What compression schemes are supported?
  1231. ___
  1232. Color QuickDraw has always supported packed PICTs. See Inside Macintosh Volume V for details on how CLUT pixmaps are packed. Under 32-Bit QuickDraw, to pack direct RGB pixmaps in PICTs, call CopyBits with the packType field in the source pixmap set to one of the following constants that apply to direct RGB pixmaps:
  1233. 0—default packing (pixelSize 16 defaults to packType 3 and pixelSize 32 defaults to packType 4)
  1234. 1—no packing
  1235. 2—remove pad byte (32-bit pixels only)
  1236. 3—run-length encoding by pixel size chunks (16-bit pixels only)
  1237. 4—run-length encoding, all of one component at the time, one scan line at a time (24-bit pixels only)
  1238. Scheme 4 will store the alpha channel also if cmpCount is set to to 4. PackSize is not used and should be set to 0 for compatibility reasons. These are the only compression techniques supported at this time.
  1239. Macintosh PICT color picture file format
  1240. Written:    1/1/90
  1241. Last reviewed:    11/21/90
  1242. Is there a general file format for color pictures that is common to all of the color paint programs? If so, where is it documented?
  1243. ___
  1244. Apple supports (and encourages developers to support) one file type for pictures: the PICT file type. Most paint-type programs handle PICT files.
  1245. A PICT file is composed of two parts in its data fork; the first 512 bytes are for the file header, which contains application-dependent information. You have to contact the individual publishers to find out their particular data structures. For example, you can contact Claris Technical Support at AppleLink CLARIS.TECH or (415) 962-0371 for the file header MacDraw writes to its files.
  1246. The rest of the data in the file is picture data as created by Macintosh QuickDraw with OpenPicture. You can find the information about this data in Volume V of Inside Macintosh (pages 84–105); this section also shows how to read/write PICT files.
  1247. You can also check the Macintosh Tech Note “Displaying Large PICT Files” for more details on the subject.
  1248. X-Refs:
  1249. DTS Macintosh Technical Note “QuickDraw’s Internal Picture Definition”
  1250. DTS Macintosh Technical Note “Displaying Large PICT Files”
  1251. Mac pixmap is clipped to visRgn defined by screenBits.bounds
  1252. Written:    1/1/90
  1253. Last reviewed:    11/21/90
  1254. I’m drawing into a large off-screen bitmap (pixmap), but anything drawn outside the 640- by 480-pixel Macintosh screen area doesn’t get written to the pixmap. Why not?
  1255. ___
  1256. When you create a new port with OpenPort or OpenCPort the visRgn is initialized to the rectangular region defined by screenBits.bounds (IM I:163). If your port has a large portRect, any drawing will be clipped to the visRgn and you will lose any drawing outside of the screenBits.bounds rectangle.
  1257. To correct this set the visRgn of the port to coincide with your port’s portRect after creating the port.
  1258. Also note that OpenPort initializes the clipRgn to a wide-open rectangular region (-32768, -32768, 32767, 32767). Some operations, like OpenPicture, can fail with this setup, so try setting clipRgn to a smaller rectangle.
  1259. X-Refs:
  1260. DTS Macintosh Technical Note “Pictures and Clip Regions”
  1261. DTS Macintosh Technical Note “Drawing into an Off-Screen Pixel Map”
  1262. Using Macintosh System 7 OpenCPicture for higher resolution
  1263. Written:    1/1/90
  1264. Last reviewed:    12/7/90
  1265. We want to use OpenCPicture for higher resolution, not for color per se. Can OpenCPicture in System 7 be used with non-Color as well as Color QuickDraw Macintosh computers?
  1266. ___
  1267. Yes, with System 7, OpenCPicture can be used to create extended PICT2 files from all Macintosh computers. Under System 6.0.7 or later, you must test for 32-Bit QuickDraw before using OpenCPicture. You can do this by calling Gestalt with the gestaltQuickdrawVersion selector. If it returns gestalt32BitQD or greater, then 32-Bit QuickDraw is installed.
  1268. How to identify 32-Bit QuickDraw version
  1269. Written:    1/1/90
  1270. Last reviewed:    11/21/90
  1271. How can my program find out which version of Macintosh 32-Bit QuickDraw is running?
  1272. ___
  1273. The following code snippet demonstrates how to use the Gestalt Manager to determine which version of 32-Bit QuickDraw is installed. There is no way to determine the version of 32-Bit QuickDraw before Gestalt. For 32-Bit QuickDraw version 1.2, Gestalt returns 2.2. Inside Macintosh Volume VI describes the Gestalt Manager in detail.
  1274. #defineTRUE0xFF
  1275. #defineFALSE0
  1276. #define Gestalttest0xA1AD
  1277. #define NoTrap0xA89F
  1278. main()
  1279. {
  1280. OSErrerr;
  1281. longfeature;
  1282. if ((GetTrapAddress(Gestalttest) != GetTrapAddress(NoTrap))) {
  1283. err = Gestalt(gestaltQuickdrawVersion, &feature);
  1284. if (!err) {
  1285. if ((feature & 0x0f00) == 0x0000)
  1286. printf ("We have Original QuickDraw version 0.%x\n", (feature & 0x00ff));
  1287. else if ((feature & 0x0f00) == 0x0100)
  1288. printf ("We have 8 Bit QuickDraw version 1.%x\n", (feature & 0x00ff));
  1289. else if ((feature & 0x0f00) == 0x0200)
  1290. printf ("We have 32 Bit QuickDraw version 2.%x\n", (feature & 0x00ff));
  1291. else
  1292. printf ("We don't have QD\n");
  1293. }
  1294. else
  1295. printf ("Gestalt err = %i\n",err);
  1296. }
  1297. else
  1298. printf ("No Gestalt\n");
  1299. }
  1300. Macintosh QDError function under System 6 and System 7
  1301. Written:    1/1/90
  1302. Last reviewed:    12/7/90
  1303. Under what System 7 and System 6 conditions is it legal to call the Macintosh QDError function?
  1304. ___
  1305. Under System 7, QDError can be called from all Macintosh computers. (System 7 supports RGBForeColor, RGBBackColor, GetForeColor, and GetBackColor for all Macintosh computers as well.) On a non-Color QuickDraw Macintosh, QDError always returns a “no error.” Under System 6, QDError cannot be used for non-Color QuickDraw Macintosh systems.
  1306. Macintosh CopyBits transfer modes changed for System 7
  1307. Written:    1/1/90
  1308. Last reviewed:    12/7/90
  1309. Why do some Macintosh CopyBits transfer modes produce different results for System 7 than for System 6?
  1310. ___
  1311. Under System 6, the srcOr, srcXor, srcBic, notSrcCopy, notSrcOr, notSrcXor, and notSrcBic transfer modes do not produce the same effect for a 16- or 32-bit (direct) pixel map as for an 8-bit or shallower (indexed) pixel map. With Color QuickDraw these classic transfer modes on direct pixel maps aren’t color-based; they’re pixel-value-based. Color QuickDraw performs logical operations corresponding to the transfer mode on the source and destination pixel values to get the resulting pixel value.
  1312. For example, say that a multicolored source is being copied onto a black-and-white destination using the srcOr transfer mode, and both the source and destination are 8 bits per pixel. Except in unusual cases, the pixel value for black on an indexed pixel map has all its bits set, so an 8-bit black pixel has a pixel value of $FF. Similarly, the pixel value for white has all its bits clear, so an 8-bit white pixel has a pixel value of $00. CopyBits takes each pixel value of the source and performs a logical OR with the corresponding pixel value of the destination. Using OR to combine any value with 0 results in the original value, so using OR to combine any pixel value with the pixel value for white results in the original pixel value. Using OR to combine any value with 1 results in 1, so using OR to combine any pixel value with the pixel value for black results in the pixel value for black. The resulting image shows the original image in all areas where the destination image was white and shows black in all areas where the destination image was black.
  1313. Take the same example, but this time make the source and destination 32 bits per pixel. The direct-color pixel value for black is $00000000 and the direct-color pixel value for white is $00FFFFFF. CopyBits still performs a logical OR on the source and destination pixel values, but notice what happens in this case. Using OR to combine any source pixel value with the pixel value for white results in white, and using OR to combine any source pixel value with the pixel value for black results in the original color. The resulting image shows the original image in all areas where the destination image was black and shows white in all areas where the destination image was white—roughly the opposite of what you see on an indexed pixel map.
  1314. The newer transfer modes addOver, addPin, subOver, subPin, adMax, and adMin work consistently at all pixel depths, and often, though not always, correspond to the theoretical effect of the old transfer modes. For example, the adMin mode works similarly to the srcOr mode on both direct and indexed pixel maps. Also, 1-bit deep source pixel maps work consistently and predictably regardless of the pixel depth of the destination even with the old transfer modes.
  1315. Under system software version 7.0, the old transfer modes now perform by calculating with colors rather than pixel values. You’ll find that transfer modes like srcOr and srcBic work much more consistently even on direct pixel maps.
  1316. Which QuickDraw versions support SetEntries
  1317. Written:    3/3/92
  1318. Last reviewed:    6/30/92
  1319. I’m calling SetEntries to update the on-screen CLUT. Who implements this call? Does 32-Bit QuickDraw? In other words, does the 32-Bit QuickDraw INIT need to be around for this to work? What about monochrome machines? 
  1320. I’m creating off-screen buffers by hand instead of using GWorlds. Is this the proper way of doing off-screen buffering when we don’t want to require the user to have 32-Bit QuickDraw?
  1321. ___
  1322. SetEntries is part of the Color Manager, which exists with all Color QuickDraw versions. A good rule of thumb to follow is that if it is documented in Inside Macintosh Volume V, you don’t need 32-Bit QuickDraw to use it. Inside Macintosh Volume V documents standard Color QuickDraw. SetEntries does not work on monochrome Macintosh models, including the Classic II, SE, and PowerBooks.
  1323. Off-screen buffering: You should always use GWorlds if they exist; use Gestalt to test for them. This will assure that you can take advantage of the latest speed improvements. It is important to remember that under System 7 NewGWorld and accompanying calls are present in all Macintosh computers including black-and-white systems such as Classic and PowerBook 100 systems.
  1324. Macintosh pixel map maximum rowBytes change
  1325. Written:    4/22/91
  1326. Last reviewed:    6/10/91
  1327. The Color QuickDraw section of Inside Macintosh Volume VI states that the restriction on the rowBytes field in a pixmap has been relaxed from $2000 to $4000. When did this happen? Is it true for all 32-Bit QuickDraw versions? This affects our user configuration recommendations.
  1328. ___
  1329. The maximum rowBytes extension to $3FFF or less applies only to 32-bit QuickDraw. Using pixmaps with rowBytes greater than $1FFF when 32-bit QuickDraw is not present is likely to cause problems such as garbage images or system crashes. Remember that 32-bit QuickDraw is always present under System 7.0.
  1330. Use assembly to flip a 24-bit off-port color pixmap
  1331. Written:    5/7/91
  1332. Last reviewed:    7/25/91
  1333. What’s the best approach to horizontally flip a 24-bit off-port color pixmap?
  1334. ___
  1335. Unfortunately, you won’t be able to use CopyBits for this kind of procedure; you’ll have to write your own routine to move each pixel. I’d suggest doing this in assembly language to squeeze the best possible performance out of your code.
  1336. Construct a 'clut' instead of changing b/w palette entries
  1337. Written:    6/10/91
  1338. Last reviewed:    8/1/91
  1339. How can I change the first and last (white and black) entries in a Macintosh palette?
  1340. ___
  1341. The answer to your question about changing the black and white entries in a palette is a little strange. You can’t simply change the palette associated with an on-screen window, because too many portions of the Toolbox/OS assume that the first entry is white and the last entry is black.
  1342. However, what you can do is create an off-screen GWorld and construct a 'clut' for it that does what you want. Creating the 'clut' is fairly straightforward:
  1343. /* Making a reversed gray-scale color table */
  1344. CTabHandle offColors;
  1345. offColors = (CTabHandle) NewHandleClear (sizeof (ColorTable) + 255 *
  1346.               sizeof (ColorSpec));
  1347. (**offColors).ctSize = 255;
  1348. for (index = 0; index <= (**offColors).ctSize; index++)
  1349.   {
  1350.     (**offColors).ctTable [index].value = index;
  1351.     (**offColors).ctTable [index].rgb.red = (index << 8) | index;
  1352.     (**offColors).ctTable [index].rgb.green = (index << 8) | index;
  1353.     (**offColors).ctTable [index].rgb.blue = (index << 8) | index;
  1354.   }
  1355. (**offColors).ctFlags = 0;
  1356. (**offColors).ctSeed = GetCTSeed ();
  1357. Note that using this 'clut' with an off-screen GWorld will work fine except if you attempt to draw text into the GWorld. Apparently drawing text off screen carries the same assumptions that all drawing does on screen.
  1358. Once you have done your off-screen drawing with the reversed 'clut' as described above, all that remains is to CopyBits from your off-screen GWorld to your on-screen window. Your on-screen window will need the appropriate palette. Fortunately, constructing that palette from the 'clut' is trivial:
  1359. /* Make a palette out of it */
  1360. aPalette = NewPalette (offColors, (**offColors).ctSize + 1, pmTolerant, 0);
  1361. Attaching this palette to the window will cause the correct remapping to occur when you CopyBits from the GWorld to the window, and everything should look just fine.
  1362. Why PlotCIcon requires GetCIcon instead of Get1Resource
  1363. Written:    4/26/91
  1364. Last reviewed:    6/17/91
  1365. Why do I have to use GetCIcon(resID) instead of Get1Resource('cicn',resID) forPlotCIcon to work correctly?
  1366. ___
  1367. You apparently thought something that, at first, I thought also: that GetCIcon(resID) is just a utility routine that translates to Get1Resource('cicn',resID). However, this is not the case; GetCIcon not only gets the 'cicn' resource, but it also performs some minor surgery on the results, fills in some placeholder fields in the resource data, and the like. Basically, PlotCIcon can’t work without the things that GetCIcon does.
  1368. CopyBits maps source pixmap colors to GDevice inverse table
  1369. Written:    4/3/91
  1370. Last reviewed:    6/17/91
  1371. I’m trying to draw off screen so I made my own CGrafPort, pixmap, and color table, but when I draw into it, the colors come out all wrong. What’s going on here?
  1372. ___
  1373. It’s a very common misconception that CopyBits maps the colors available in the source pixmap’s color table to the colors available in the destination pixmap’s color table.
  1374. What actually happens is that CopyBits maps the colors in the source pixmap to the colors available in the current GDevice’s inverse table. See Inside Macintosh Volume V, pages 137 through 139 for a description of inverse tables. Inverse tables is a backwards color table. With a color table, you use a pixel value as an index into the table to return a color. With an inverse table, you use a color-like value as an index into the table to return a pixel value. When CopyBits maps colors from one pixel map to another, it takes a source pixel value, uses the source pixmap’s color table to get the corresponding color, and uses that color as an index into the current GDevice’s inverse table to get the pixel value of the closest color in the destination pixmap’s color table.
  1375. Generally speaking, every conceivable color table has exactly one conceivable inverse table. If you alter the contents of a color table, then the inverse table must likewise be altered. It’s just like numbers: for any number you give me, I can give you its negative. For any color table you give me, MakeITable can give you its inverse table. MakeITable is documented in Inside Macintosh Volume V, page 142.
  1376. Think of the current GDevice as an implied parameter to CopyBits. If you don’t deal with GDevices at all, then the current GDevice is always the main screen’s GDevice as far as you’re concerned. Color QuickDraw often switches between different screens’ GDevices so that you can draw to multiple screens, but that’s all handled behind your back. If you create a pixmap, give it a color table, and CopyBits to it, then the main screen’s GDevice’s inverse table is used to map colors from the source pixmap. That’s OK as long as your destination pixmap’s color table is compatible with the main screen’s inverse table. If you change the depth and/or color table of the main screen, and then still CopyBits to this same pixmap with the same old depth and color table, then things won’t work correctly because the main screen’s GDevice’s inverse table changes, making it incompatible with your destination pixmap’s color table. This problem usually manifests itself as incorrect colors, but it can result in crashes.
  1377. To fix this, you’ll have to remove your reliance on the main screen’s GDevice. To do that you’ll have to make your own GDevice. There’s a routine called NewGDevice, but it always makes the GDevice in the system heap. Instead, you should just call NewHandle to allocate a GDevice record yourself. Here’s what the fields should hold:
  1378. gdRefNum—The GDevice has no driver, so set this to 0.
  1379. gdID—It doesn’t matter what this is set to—might as well set it to 0.
  1380. gdType—Set this to 2 if the off-screen uses direct colors (16 or 32 bits per pixel) or 0 if the off-screen uses a color table (1 through 8 bits per pixel).
  1381. gdITable—Allocate a small (maybe just a 2-byte) handle for this field. After you’re done setting up this GDevice and your off-screen pixmap, color table (if any), and CGrafPort, then set this GDevice as the current GDevice by calling SetGDevice. Then call MakeITable, passing it NIL for both the color table and inverse table parameters, and 0 for the preferred inverse table resolution.
  1382. gdResPref—I’d guess that more than 99.9 percent of all inverse tables out there have a resolution of 4. Unless you have some reason not to, I’d recommend the same here.
  1383. gdSearchProc—Set to NIL. Use AddSearch if you want to use a SearchProc.
  1384. gdCompProc—Set to NIL. Use AddComp if you want to use a CompProc.
  1385. gdFlags—Set to 0 initially, and then use SetDeviceAttribute after you’ve set up the rest of this GDevice.
  1386. gdPMap—Set this to be a handle to your off-screen pixmap.
  1387. gdRefCon—Set this to whatever you want.
  1388. gdNextGD—Set this to nil.
  1389. gdRect—Set this to be equal to your off-screen pixmap’s bounds.
  1390. gdMode—Set this to -1. This is intended for GDevices with drivers anyway.
  1391. gdCCBytes—Set to 0.
  1392. gdCCDepth - Set to 0.
  1393. gdCCXData - Set to 0.
  1394. gdCCXMask - Set to 0.
  1395. gdReserved - Set to 0.
  1396. For gdFlags, you should use SetDeviceAttribute to set the noDriver bit and the gDevType bit. You should set the gDevType bit to 1 even if you have a monochrome color table. The 0 setting was only used when monochrome mode was handled by the video driver, and 32-Bit QuickDraw eliminated that convention. Your GDevice doesn’t have a driver anyway.
  1397. Once this is done, the GDevice and the off-screen pixmap should be treated as inseparable. When you CopyBits or draws into the pixmap, first call SetGDevice to set its GDevice as the current GDevice. When that’s done, call SetGDevice to restore the previous GDevice. Doing this insulates you from changes in a screen’s GDevice.
  1398. If you alter your pixmap’s color table, you should make sure you update the ctSeed of that color table, either by assigning to it the result of GetCTSeed (documented on page 143 of Inside Macintosh Volume V) or by passing a handle to the color table to CTabChanged. The next time that pixmap is drawn into, Color QuickDraw will update your GDevice’s inverse table automatically when it realizes that the ctSeed is different from the current GDevice (which had better be yours) inverse table’s iTabSeed.
  1399. GWorlds work this way on Color QuickDraw machines. Every GWorld comes with a pixmap and a GDevice. When you call SetGWorld, that sets both the GWorld and its GDevice as current.
  1400. How Macintosh system draws small color icons
  1401. Written:    3/31/92
  1402. Last reviewed:    5/21/92
  1403. The code I added to my application’s MDEF to plot small icons in color works except for when I hold the mouse over an item with color. The color of the small icons is wrong because it’s just doing an InvertRect. When I drag over the Apple menu, the menu inverts behind the icon but the icon is untouched. Is this done by brute force, redrawing the small icon after every InvertRect?
  1404. ___
  1405. As you figured out, the Macintosh system draws color icons, such as the Apple icon on the menu bar, every time the title has to be inverted.
  1406. The actual sequence of calls is (more or less) as follows: first InvertRect is called to black the menu title and then PlotIconID is called to draw the icon in its place. The advantage of using PlotIconID is that you don’t have to worry about the depth and size of the icon being used. The system picks the best match from the family whose ID is being passed, taking into consideration the target rectangle and the depth of the device(s) that will contain the icon’s image.
  1407. The Icon Utilities call PlotIconID is documented in the Macintosh Technical Note, “Drawing Icons the System 7 Way.” Just in case you don’t have your stack at hand, the interface is:
  1408.     IconAlignmentType    =    INTEGER;
  1409.     IconTransformType    =    INTEGER;
  1410.     FUNCTION PlotIconID(theRect: Rect;
  1411.                         align: IconAlignmentType;
  1412.                         transform: IconTransformType;
  1413.                         theResID: INTEGER): OSErr;
  1414.         INLINE    $303C, $0500, $ABC9;
  1415.     
  1416. typedef short    IconAlignmentType;
  1417. typedef short    IconTransformType;
  1418. pascal OSErr PlotIconID(const Rect *theRect,
  1419.                             IconAlignmentType align,
  1420.                             IconTransformType transform,
  1421.                             short theResID)
  1422.     = {0x303C, 0x0500, 0xABC9};
  1423. Please refer to the Tech Note referenced above for more details on using the calls.
  1424. Spooling and preserving Macintosh QuickDraw pixmap depth
  1425. Written:    2/11/92
  1426. Last reviewed:    9/15/92
  1427. When a picture that contains a pixmap is spooled into a window, how and when is the depth of the pixmap in the picture converted to the depth of the screens the window is on?
  1428. ___
  1429. When a picture is spooled in, if QuickDraw encounters any bitmap opcode, it allocates a pixmap of the same depth as the data associated with the bitmap opcode, expands the data into the temporary pixmap, and then calls StdBits. StdBits is what triggers the depth and color conversions as demanded by the color environment (depth, color table, black-and-white settings) of the devices the target port may span (as when a window crosses two or more screens).
  1430. If there’s not enough memory in the application heap or in the temporary memory pool, QuickDraw bands the image down to one scan line and calls StdBits for each of these bands. Note that if you’re providing your own bitsProc, QuickDraw will call it instead of StdBits.
  1431. This process is the same when the picture is in memory, with the obvious exception that all the picture data is present; the color mapping occurs when StdBits does its stuff.
  1432. Determining the resolution of a PICT
  1433. Written:    6/10/92
  1434. Last reviewed:    9/15/92
  1435. In a version 2 picture, the picFrame is the rectangular bounding box of the picture, at 72 dpi. I would like to determine the bounding rectangle at the stored resolution or the resolution itself. Is there a way to do this without reading the raw data of the PICT resource itself?
  1436. ___
  1437. With regular version 2 PICTs (or any pictures), figuring out the real resolution of the PICT is pretty tough. Applications use different techniques to save the information. But if you make a picture with OpenCPicture, the resolution information is stored in the headerOp data, and you can get at this by searching for the headerOp opcode in the picture data (it’s always the second opcode in the picture data, but you still have to search for it in case there are any zero opcodes before it). Or you can use the Picture Utilities Package to extract this information.
  1438. With older picture formats, the resolution and original bounds information is sometimes not as obvious or easily derived. In fact, in some applications, the PICT’s resolution and original bounds aren’t stored in the header, but rather in the pixel map structure(s) contained within the PICT.
  1439. To examine these pixmaps, you’ll first need to install your own bitsProc, and then manually check the bounds, hRes, and vRes fields of any pixmap being passed. In most cases the hRes and vRes fields will be set to the Fixed value 0x00480000 (72 dpi); however, some applications will set these fields to the PICT’s actual resolution, as shown in the code below.
  1440. Rect            gPictBounds;
  1441. Fixed            gPictHRes, gPictVRes;
  1442. pascal void ColorBitsProc (srcBits, srcRect, dstRect, mode, 
  1443.     maskRgn)
  1444. BitMap        *srcBits;
  1445. Rect            *srcRect, *dstRect;
  1446. short            mode;
  1447. RgnHandle    maskRgn;
  1448. {
  1449.     PixMapPtr    pm;
  1450.     pm = (PixMapPtr)srcBits;
  1451.     gPictBounds = (*pm).bounds;
  1452.     gPictHRes = (*pm).hRes;        /* Fixed value */
  1453.     gPictVRes = (*pm).vRes;        /* Fixed value */
  1454. }
  1455. void FindPictInfo(picture)
  1456. PicHandle picture;
  1457. {
  1458.     CQDProcs        bottlenecks;
  1459.     SetStdCProcs (&bottlenecks);
  1460.     bottlenecks.bitsProc = (Ptr)ColorBitsProc;
  1461.     (*(qd.thePort)).grafProcs = (QDProcs *)&bottlenecks;
  1462.     DrawPicture (picture, &((**picture).picFrame));
  1463.     (*(qd.thePort)).grafProcs = 0L;
  1464. }
  1465. Adding Color With CopyBits
  1466. Imaging    M.IM.ColorCopyBits
  1467. Revised by        March 1988
  1468. Written by:    Chris Derossi    November 1987
  1469. Inside Macintosh Volume V states that the foreground and background colors are applied to an image during a CopyBits or CopyMask call. Accidental use of this feature can create bizarre coloring effects. This note explains what happens, how to avoid problems, and how to use it.
  1470. What Happens
  1471. Color QuickDraw has a feature that will allow you to convert a monochrome image to a color image. During a CopyBits or CopyMask call, if the foreground and background colors are not black and white, respectively, Color QuickDraw performs the following operation on every pixel being copied:
  1472.     NOTE: color table index = pixel value
  1473.     s = color table index of source pixel
  1474.     fg = color table index of foreground color
  1475.     bg = color table index of background color
  1476.     ColoredPixelValue = (NOT(s) AND bg) OR (s AND fg)
  1477. If your source image contains only black and white pixels, then all black pixels would become the foreground color and all white pixels would become the background color. This is because the color table index for white is all zeros and the color table index for black is all ones.
  1478. For example, suppose your source image was a 4-bit deep color PixMap. Then the color table index for white (in binary) is 0000 and the index for black is 1111. And let’s suppose that your foreground color is green with an index of 1101 while your background color is red with an index of 0011. Then for the black pixels, the above procedure produces:
  1479.     ColoredPixelValue = (NOT(1111) AND 0011) OR (1111 AND 1101)
  1480.          1101         = (  0000    AND 0011) OR (1111 AND 1101)
  1481. And the operation on the white pixels yields:
  1482.     ColoredPixelValue = (NOT(0000) AND 0011) OR (0000 AND 1101)
  1483.          0011         = (  1111    AND 0011) OR (0000 AND 1101)
  1484. Possible Problems
  1485. This colorizing will only work on 2-color (i.e. black and white) images, and then only if those colors occupy the first and last entries in the color table. Trying to colorize colors that are not the first and last color table entries will yield unexpected results.
  1486. This is mainly due to the fact that the colorizing algorithm uses a pixel’s color table index value rather than its actual RGB color. To illustrate this, let’s assume that foreground and background colors are as above, and your image contains yellow with a color table index of 1000. The colorizing operation would give:
  1487.     ColoredPixelValue = (NOT(1000) AND 0011) OR (1000 AND 1101)
  1488.          1011         = (  0111    AND 0011) OR (1000 AND 1101)
  1489. Since the color table may have any RGB color at the resulting index position, the final color may not even be close to the source, foreground, or background colors.
  1490. Similar things occur if you are trying to colorize a black and white image when white and black do not occupy the first and last positions in the color table.
  1491. The bottom line rules for CopyBitsing in a color environment are these:
  1492. •    Thou shalt set thy background color to white and thy foreground color to black before calling CopyBits or CopyMask, unless thou art coloring a monochrome image.
  1493. •    Thou shalt, when colorizing, make sure that the first color table entry is white and the last     color table entry is black.
  1494. The second rule is easy to follow because the default color tables are constructed properly, and if you are using the Palette Manager (and you are, right?) then it will make sure that the color tables obey this rule.
  1495. How To Colorize—An Example
  1496. This code fragment shows how to implement a color fill, like the paint bucket in MacPaint. It relies on three main things: SeedCFill for calculating the fill area, CopyMask for actually changing the bits, and QuickDraw colorizing.
  1497. PROCEDURE PaintBucket(where: Point; paintColor: RGBColor);
  1498.     VAR
  1499.         savedFG    : RGBColor;
  1500.         offBits    : BitMap;
  1501.     BEGIN
  1502.         {First, create an offscreen bitmap.}
  1503.         offBits.bounds := myWindow^.portRect;
  1504.         WITH offBits.bounds DO BEGIN
  1505.             offBits.rowBytes := ((right - left + 15) DIV 16) * 2;
  1506.             offBits.baseAddr := NewPtr((bottom-top) * offBits.rowBytes);
  1507.         END;
  1508.         {Check MemError here! Make sure NewPtr succeeded!}
  1509.         SeedCFill(myWindow^.portBits,offBits,myWindow^.portRect,
  1510.             myWindow^.portRect,where.h,where.v,NIL,0);
  1511.         GetForeColor(savedFG);
  1512.         RGBForeColor(paintColor);
  1513.         CopyMask(offBits,offBits,myWindow^.portBits,myWindow^.portRect,
  1514.             myWindow^.portRect,myWindow^.portRect);
  1515.         RGBForeColor(savedFG);
  1516.         DisposPtr(offBits.BaseAddr);
  1517.     END;
  1518. The variable offBits is an offscreen BitMap (not a PixMap) with bounds = myWindow^.portRect.  SeedCFill effectively creates, in the offscreen BitMap,  a monochrome image of the bits that we want to paint. Since offBits contains the exact bits that we want to paint, it is used as both the source image and the mask for CopyMask.
  1519. By setting the foreground color to the desired paint color, the result is a colorized version of the mask (the paint area) being copied onto the window’s PixMap without affecting any other bits.
  1520. Further Reference:
  1521. •    Color QuickDraw
  1522. Deaccelerated _CopyBits & 8•24 GC QuickDraw
  1523. Imaging    M.IM.GCQDCopybits
  1524. Written by:    Guillermo A. Ortiz    February 1991
  1525. This Technical Note discusses conditions that may cause _CopyBits to slow down when QuickDraw acceleration is on via the Apple 8•24 GC Display Card.
  1526. Introduction
  1527. When a drawing call is issued, GC IPC (Interprocess Communication) takes control of the call and passes it to GC QuickDraw.  After the normal port set up (which involves caching the port parameters if this is the first drawing call after the port was set), GC QuickDraw returns control to the application through the IPC and performs, in parallel, the drawing to its own monitor as well as any other monitors that may be affected by  the operation.  The application then continues its execution, probably issuing more drawing calls that get executed in the same asynchronous manner.
  1528. The result of this mode of operation is improved performance, since the application gets control back immediately after issuing the call and the GC QuickDraw moves video data to its own video buffer as well as that of other cards in a more rapid manner by using block transfers and without requiring any action by the main processor.
  1529. _CopyBits Conforms To The Same Scheme, Except…
  1530. _CopyBits conforms to the same operational scheme, but there are some instances in which GC QuickDraw cannot perform the call in parallel; in this cases it is even possible to suffer a performance loss, since the whole call may have to be completed before control is given back to the application and GC QuickDraw has to make calls and access data across the NuBus™.
  1531. The situations that compromise GC QuickDraw parallel operation are as follows:
  1532. •    When the destination device has a SearchProc installed and the source color environment is different from the destination environment.
  1533.     QuickDraw calls a SearchProc whenever the source and destination have different depths and when two indexed pixel maps have different color tables, even though their depths may be identical.  When GC acceleration is enabled, these conditions cause the following two types of behavior, dependent upon the source pixel map:
  1534. •    If the source is an indexed pixel map, then GC QuickDraw executes the part of the setup that involves calling the SearchProc, returns control to the main processor, then completes the call in parallel.  The act of calling the SearchProc before returning control makes the call slower than when no SearchProc is involved, since parallel operation does not occur throughout the whole call.
  1535. •    If the source is a direct RGB pixel map, then GC QuickDraw has to call the SearchProc for every pixel that is drawn, and the application does not regain control until after the call to _CopyBits has been completed.
  1536. •    When the source or destination is offscreen and not created using a GWorld.
  1537.     GC QuickDraw has no way to detect when an application is going to manipulate a pixel map it has created in memory, so if it has to draw to or copy from such a PixMap, GC QuickDraw has to complete the operation before returning control to the application.
  1538.     This behavior is contrary to the case when using a GWorld for offscreen environments, since in the case of a GWorld, GC QuickDraw is alerted by the call to _GetPixBaseAddr that the application is getting ready to directly change the pixels.  This is the reason why it is so important that applications call _GetPixBaseAddr every time they are about to manipulate a GWorld pixel map directly.
  1539. •    When the source PixMap has a color table that uses indexes that refer to a palette.
  1540.     QuickDraw now allows a color table to have indexes that point to entries in the palette associated with the destination window; when bit 14 in the ctFlags field is set, the value fields in the color table are treated as palette entries.  When such a PixMap is the source for _CopyBits, then GC QuickDraw has to make a number of calls to the Palette Manager as part of the setup before returning control and completing the call.
  1541.     This case is similar to that of a indexed pixel map when a SearchProc is involved; therefore, it only implies a partial loss of parallelism; it is good to keep in mind that this case can only occur when the source PixMap is indexed.
  1542. Further Reference:
  1543. •    Inside Macintosh, Volumes V & VI, Color QuickDraw
  1544. •    d e v e l o p, “Macintosh Display Card 8•24 GC:  The Naked Truth,” July 1990.
  1545. •    Technical Note #275, 32-Bit QuickDraw:  Version 1.2 Features
  1546. •    Developer Notes for the Macintosh Display Cards 4•8, 8•24 and 8•24 GC (APDA, M085TLL/A)
  1547. NuBus is a trademark of Texas Instruments.
  1548. Drawing Icons
  1549. Imaging    M.IM.DrawingIcons
  1550. Written by:    Jim Friedlander    October 1985
  1551. Using resources of type ICON allows drawing of icons in srcOr mode.  Using resources of type ICN# allows for more variety when drawing icons.
  1552. There are two different kinds of resources that contain icons: ICON and ICN#. An ICON is a 32 by 32 bit image of an icon and can be drawn using the following Toolbox Utilities calls:
  1553.     MyIconHndl:= GetIcon(iconID);
  1554.     PlotIcon(destRect,iconID);
  1555. While very convenient, this method only allows the drawing of icons in SrcOr mode (as in the MiniFinder). The Finder uses resources of type ICN# to draw icons on the desktop. Because the Finder uses ICN#s, it can draw icons in a variety of ways.
  1556. An ICN# resource is a list of 32 by 32 bit images that are grouped together. Common convention has been to group two 32 by 32 bit images together in each ICN#. The first image is the actual icon, the second image is the mask for the icon. To get a handle to an ICN#, we would use something like this:
  1557. TYPE
  1558.     iListHndl    = ^iListPtr;
  1559.     iListPtr     = ^iListStruct;
  1560.     iListStruct  = record
  1561.         icon : packed array[0..31] of Longint;
  1562.         mask : packed array[0..31] of Longint;
  1563.     End; {iListStruct}
  1564. VAR
  1565.     myILHndl      : iListHndl;            {handle to an ICN#}
  1566.     iBitMap       : BitMap;          {BitMap for the icon}
  1567.     mBitMap       : BitMap;          {BitMap for the mask}
  1568.     MyILHndl:= iListHndl(GetResource('ICN#',iconID));          
  1569.     if MyILHndl = NIL then HandleError; 
  1570.         {and exit or whatever is appropriate}
  1571. Once we have a handle to the icons, we need to set up two bitMaps that we will be using later in CopyBits: 
  1572.         SetRect(icnRect,0,0,32,32);                { define the icon's 'bounds'}
  1573.     With iBitMap do Begin
  1574.          baseAddr:= @MyILHndl^^.icon;    
  1575.          rowbytes:= 4;                            { 4 * 8 =32}
  1576.          bounds:= icnRect;
  1577.      End; {with}
  1578.       With mBitMap do Begin
  1579.          baseAddr:= @MyILHndl^^.mask;
  1580.          rowbytes:= 4;
  1581.          bounds:= icnRect;
  1582.       End; {with}
  1583. Icons can represent desktop objects that are either selected or not. Folder and volume icons can either be open or not. The object (or the volume it is on) can either be online or offline. The Finder draws icons using all permutations of open, selected and online:
  1584. Drawing icons as non-open is basically the same for online and offline volumes. We need to punch a hole in the desktop for the icon. This is analogous to punching a hole in dough with an irregular shaped cookie-cutter. We can then sprinkle jimmies* all over the cookie and they will only stick in the area that we punched out (the mask). We do this by copyBitsing the mask onto the desktop (whatever pattern) to our destRect. For non-open, non-selected icons: 
  1585. we use the SrcBic mode so that we punch a white hole:
  1586.     SetRect(destRect,left,top,left+32,top+32);
  1587.     CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); 
  1588. Then we XOR in the icon:
  1589.      CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXor,NIL);
  1590. That’s all there is to drawing an icon as non-open, non-selected. To draw the icon as non-open, selected:
  1591.          
  1592. we will OR in the mask, causing a mask-shaped BLACK hole to be punched in the desktop:
  1593.     CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL); 
  1594. Then, as before, we XOR in the icon:
  1595.     CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXOr,NIL);
  1596. To draw icons as non-opened for offline volumes:
  1597. we need to do a little more work. We need to XOR a ltGray pattern into the boundsRect of the icon. We will then punch the hole, draw the icon and then XOR out the ltgray pattern that does not fall inside the mask. So, to draw the icon as offline, non-open, non-selected we would:
  1598.     GetPenState(OldPen);        {save the pen state so we can restore it}
  1599.     PenMode(patXor);
  1600.       PenPat(ltGray);
  1601.       PaintRect(destRect);        {paint a ltGray background for icon}
  1602.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); {punch}
  1603.      PaintRect(destRect);{XOR out bits outside of the mask, leaving the mask} 
  1604.                 {filled with ltGray}
  1605.                                                 
  1606.                                            CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);{ OR in }                                                                                   { the icon to the ltGray mask}
  1607. SetPenState(OldPen);                           {restore the old pen state}
  1608. To draw the icon as offline, non-open, selected:
  1609. we would use a similar approach:
  1610.         GetPenState(OldPen);        { save the pen state so we can restore it}
  1611.     PenMode(patXor);
  1612.     PenPat(dkGray);        { the icon is selected, so we need dkGray }
  1613.       PaintRect(destRect);        { paint a dkGray background for icon }
  1614.     {punch a hole in the background}
  1615.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  1616.     PaintRect(destRect);        {XOR out bits outside of the mask, leaving
  1617.                      the mask filled with dkGray}
  1618.     {BIC the icon to the dkGray mask}
  1619.     CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  1620.       SetPenState(OldPen);         {restore the old pen state}
  1621. Drawing the opened icons requires one less step. We don’’t have to CopyBits the icon in, we just use the mask. Online and offline icons are drawn the same way. To draw icons as open, selected:
  1622. we do the following:
  1623.         GetPenState(OldPen);        {save the pen state so we can restore it}
  1624.       PenMode(patXor);
  1625.       PenPat(dkGray);        { the icon is selected, so we need dkGray }
  1626.        PaintRect(destRect);        { paint a dkGray background for icon}
  1627.     {punch a hole in the background}
  1628.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  1629.   
  1630.       PaintRect(destRect);      {XOR out bits outside of the mask, leaving 
  1631.                     the mask filled with dkGray}
  1632.       SetPenState(OldPen);        {restore the old pen state}
  1633. To draw icons as open, non-selected:
  1634. we just need to change one line from above. Instead of XORing with a dkGray pattern, we use a ltGray pattern:
  1635.       PenPat(ltGray);        {icon is non-selected, so we need ltGray}
  1636. These techniques will work on any background, window-white or desktop-gray and all patterns in between. Have fun.
  1637. * jimmies : little bits of chocolate
  1638. Further Reference:
  1639. •    QuickDraw
  1640. •    Toolbox Utilities
  1641. Drawing Icons the System 7 Way
  1642. Imaging    M.IM.IconDrawing
  1643. Revised by:    Don Moccia and C.K. Haun <TR>    October 1992
  1644. Written by:    Jim Mensch and David Collins    October 1991
  1645. This Technical Note describes how to utilize the built-in System 7 icon drawing utility. Use this information to better conform to the System 7 visual human interface.
  1646. Changes since May 1992: In this Note, we replaced the C and Pascal interface files and corrected the related text. So much text was tweaked that change bars are used only on code changes. 
  1647. Introduction
  1648. With the introduction of System 7 for the Macintosh, Apple has defined a new look and feel for many screen elements that better utilize color. Among those redefined elements are the icons drawn by the Finder and other system components. Until now, Apple has not documented how to draw icons the way the Finder does in System 7.
  1649. This Technical Note discusses the icon toolkit calls that the Finder uses to draw and manipulate the screen icons. Two of the calls, PlotIconID and PlotCIconHandle, are the ones you will probably use the most since they simply deal with drawing single icons to the screen. Some parts of the toolbox require that an icon family handle be passed to them to allow the drawing of color icons. The icon toolkit provides calls that allow you to create, draw, and manipulate these handles.
  1650. The New 'ic' Type Resources
  1651. PlotIconID and PlotCIconHandle allow the use of standard CIcons as documented in Inside Macintosh Volume V. The PlotIconID call also permits the use of a new set of icon resources documented in Inside Macintosh Volume VI, Chapter 9. This new set is a collection of different icons, representing a single Finder object, into a family. Each member of the family has the same resource ID as the 'ICN#', and a resource type indicating the icon data it contains. Currently Apple has defined three sizes of icons and three bit depths for each size. The sizes are large (32 by 32 pixels), small (16 by 16 pixels), and mini (12 by 12 pixels). The bit depths are 1, 4, and 8. The actual resource types are defined as:
  1652. Large1BitMask    =    'ICN#';
  1653. Large4BitData    =    'icl4';
  1654. Large8BitData    =    'icl8';
  1655. Small1BitMask    =    'ics#';
  1656. Small4BitData    =    'ics4';
  1657. Small8BitData    =    'ics8';
  1658. Mini1BitMask     =    'icm#';
  1659. Mini4BitData     =    'icm4';
  1660. Mini8BitData     =    'icm8';
  1661. The 1-bit-per-pixel member of each size also contains the mask data for all icons of that size (yes, this means that all your icons of a certain size must have the same mask). A 1-bit-per-pixel member must exist for each icon size that PlotIconID uses. The icon size used is determined by the size of the destination rectangle. If the destination rectangle is greater than 16 pixels on a side then the large icon will be used. If the rectangle is 13–16 pixels on both sides, the small icon will be used. If it is 12 or less on each side, the mini-icon will be used. The bit depth is determined by the device of the grafPort you plot into at drawing time. Be sure to create a color grafPort when you want to use color icons.
  1662. Icon Families (or Suites and Caches As the Tool Set Refers to Them)
  1663. An icon family is simply a collection of icon handles that contain up to one image of each bit depth and size for a given icon. The family can be fully populated (every possible size or depth available), or it can have only those icons that exist or are needed. By using families, you remove the need to determine which size or depth of icon to use when drawing into a given rectangle. Several system routines, the Notification Manager for example, can take an icon family handle when an icon is requested. This permits them to use the proper color icons if available. In the case of a sparsely populated icon family, when the proper icon is not available, the icon toolkit will pick a substitute to produce the best results.
  1664. An icon cache is a family that also has a ProcPtr and a refCon. The main difference between a cache and a family is that the elements of the cache’s array are sparsely populated. When using an icon cache, the system either will use the entry in the icon family portion of the cache or, if the desired element is empty, it will call the procedure pointed to by the ProcPtr and request the data for the icon. The procedure should have this interface:
  1665. FUNCTION IconGetter(theType: ResType;
  1666.                     yourDataPtr: Ptr): Handle;
  1667. This function should return either the icon data to be drawn or NIL to signify that this entry in the icon cache does not exist. Icon caches can be used with all icon family calls. A few extra calls are also available to manipulate icon caches.
  1668. Drawing Modes or Transforms
  1669. In addition to various sizes and bit depths, icons can be drawn with different modes or transforms. Transforms are analogous to certain Finder states for the icons. For example, the transform that you would use to show an icon of a disk that has been ejected is ttOffline. Here is a list of the available transforms:
  1670. ttNone                =    $0;
  1671. ttDisabled            =    $1;
  1672. ttOffline             =    $2;
  1673. ttOpen                =    $3;
  1674. ttSelected            =    $4000;
  1675. ttSelectedDisabled    =    (ttSelected + ttDisabled);
  1676. ttSelectedOffline     =    (ttSelected + ttOffline);
  1677. ttSelectedOpen        =    (ttSelected + ttOpen);
  1678. The actual appearance of the icon drawn by each transform type may vary with future system software, so you should always use the transform that best fits the state it represents in your application. This way you will be consistent with future changes to the look and feel of regular system icons. Note the ttSelected transform can be added to any of the other transform types.
  1679. There are also transforms that use the Finder label colors to color the icon. To determine the proper label for a file’s icon, you can check bits 1–3 of the fdFlags field in the file’s Finder info. (See the Finder Interface chapter in Inside Macintosh Volume VI for more information). These bits contain a number from 0 to 7. Simply add the corresponding ttLabel value to the transform that you give the call. The label values are defined like this:
  1680. ttLabel1    =    $0100;
  1681. ttLabel2    =    $0200;
  1682. ttLabel3    =    $0300;
  1683. ttLabel4    =    $0400;
  1684. ttLabel5    =    $0500;
  1685. ttLabel6    =    $0600;
  1686. ttLabel7    =    $0700;
  1687. Alignment
  1688. Most icons do not fully fill their rectangle, and it is sometimes necessary to draw an icon relative to other data (like menu text). In these instances it is nice to be able to have the icon move in its rectangle so that it will be at a predictable location in the destination rectangle. When drawing an icon you can pass one of these standard alignments in the alignment parameter or you can add a vertical alignment to a horizontal alignment to create a composite alignment value.
  1689. atNone                =    $0;
  1690. atVerticalCenter      =    $1;
  1691. atTop                 =    $2;
  1692. atBottom              =    $3;
  1693. atHorizontalCenter    =    $4;
  1694. atAbsoluteCenter      =    (atVerticalCenter + atHorizontalCenter);
  1695. atCenterTop           =    (atTop + atHorizontalCenter);
  1696. atCenterBottom        =    (atBottom + atHorizontalCenter);
  1697. atLeft                =    $8;
  1698. atCenterLeft          =    (atVerticalCenter + atLeft);
  1699. atTopLeft             =    (atTop + atLeft);
  1700. atBottomLeft          =    (atBottom + atLeft);
  1701. atRight               =    $C;
  1702. atCenterRight         =    (atVerticalCenter + atRight);
  1703. atTopRight            =    (atTop + atRight);
  1704. atBottomRight         =    (atBottom + atRight);
  1705. And Now (Drum Roll Please) the Calls and What to Pass
  1706. Now that we have defined every major data type we can think of, here are the actual toolkit calls themselves. One word of caution: only the ForEachIconDo call protects the handle that is passed to it, so make your icon resources nonpurgeable.
  1707. Icon Family Calls
  1708. FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  1709. NewIconSuite returns an empty icon family handle with all members set to NIL.
  1710. FUNCTION AddIconToSuite(theIconData: Handle;
  1711.                         theSuite: Handle;
  1712.                         theType: ResType): OSErr;
  1713. This call will add the data in theIconData into the suite at the location reserved for theType of icon data. AddIconToSuite will replace any old data in that slot without disposing of it, so you may want to call GetIconFromSuite to obtain the old handle (if any) to dispose of it. This call will be used most often with the NewIconSuite call to fill the empty family after it’s created.
  1714. FUNCTION GetIconFromSuite(VAR theIconData: Handle;
  1715.                           theSuite: Handle;
  1716.                           theType: ResType): OSErr;
  1717. This call will return a handle to the pixel data of the family member of theSuite specified by theType. If you intend to dispose of this handle, be sure to call AddIconToSuite with a NIL handle to zero out the family entry.
  1718. FUNCTION ForEachIconDo(theSuite: Handle;
  1719.                        selector: IconSelectorValue;
  1720.                        action: IconAction;
  1721.                        yourDataPtr: Ptr): OSErr;
  1722. This routine will call your IconAction procedure (see below) for each icon in the family specified by selector and theSuite. The selector parameter is a bit-level flag that specifies which family members to operate on; they can be added together to create composite selectors that work on several different family members. The values for selector are:
  1723. svLarge1Bit        =    $00000001;
  1724. svLarge4Bit        =    $00000002;
  1725. svLarge8Bit        =    $00000004;
  1726. svSmall1Bit        =    $00000100;
  1727. svSmall4Bit        =    $00000200;
  1728. svSmall8Bit        =    $00000400;
  1729. svMini1Bit         =    $00010000;
  1730. svMini4Bit         =    $00020000;
  1731. svMini8Bit         =    $00040000;
  1732. svAllLargeData     =    $000000FF;
  1733. svAllSmallData     =    $0000FF00;
  1734. svAllMiniData      =    $00FF0000;
  1735. svAll1BitData      =    (svLarge1Bit + svSmall1Bit + svMini1Bit);
  1736. svAll4BitData      =    (svLarge4Bit + svSmall4Bit + svMini4Bit);
  1737. svAll8BitData      =    (svLarge8Bit + svSmall8Bit + svMini8Bit);
  1738. svAllAvailableD    =    $FFFFFFFF;
  1739. The action procedure that gets called for each icon type selected for the family is a Pascal type function with the following interface:
  1740. FUNCTION IconAction(theType: ResType;
  1741.                     VAR theIcon: Handle;
  1742.                     yourDataPtr: Ptr): OSErr;
  1743. The parameter theIcon is passed by reference here so that your routine can modify the contents of the suite directly. The yourDataPtr parameter is the value passed when you called ForEachIconDo. It allows you to easily communicate with your application. The action procedure returns an OSErr. If any value other than noErr is returned, ForEachIconDo will stop processing immediately and return the error passed. (Note: This implies that the icons selected may only be partially operated on. There is no guaranteed order in which the icons get operated on.)
  1744. FUNCTION GetIconSuite(VAR theIconSuite: Handle;
  1745.                       theResID: INTEGER;
  1746.                       selector: IconSelectorValue): OSErr;
  1747. GetIconSuite will create a new icon family and fill it from the current resource chain with the icons of resource ID theResID and types indicated by selector. This is the call you will probably use most often to create an icon family. Note that if you SetResLoad(False) before making this call, the suite will be filled with unloaded resource handles.
  1748. FUNCTION PlotIconSuite(theRect: Rect;
  1749.                        align: IconAlignmentType;
  1750.                        transform: IconTransformType;
  1751.                        theIconSuite: Handle): OSErr;
  1752. This call renders the proper icon image from the passed icon family based on the bit depth of 
  1753. the display you are using and the rectangle that you have passed. The parameters align and transform are applied to the icon selected for drawing and then the icon is plotted into the current grafPort. PlotIconSuite chooses the appropriate icon based primarily on size. Once the proper icon size is determined (based on the destination rectangle), the present member of that size with the deepest bit depth that the current device can use is selected. A size category is considered present if the black-and-white member (with mask), 'ICN#', 'ics#', or 'icm#', is present. PlotIconSuite can be used for both picture accumulation and printing.
  1754. FUNCTION DisposeIconSuite(theIconSuite: Handle;
  1755.                           disposeData: BOOLEAN): OSErr;
  1756. This call disposes the icon family handle itself. In addition, if disposeData is true, any of the icon data handles that do not belong to a resource fork will also be disposed.
  1757. FUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  1758. This call allows you to specify a label to draw an icon of this suite when no label is specified in PlotIconSuite. This is used primarily to ensure that a family passed to a system routine gets drawn with the proper label. The default label can be overridden by specifying a label in PlotIconSuite.
  1759. FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  1760. GetSuiteLabel returns the label previously set with SetSuiteLabel.
  1761. Icon Cache Calls
  1762. In addition to the icon family calls, icon caches have these additional calls: 
  1763. FUNCTION MakeIconCache(VAR theHandle: Handle;
  1764.                        makeIcon: IconGetter;
  1765.                        yourDataPtr: UNIV Ptr): OSErr;
  1766. This call creates an empty icon cache similar to NewIconSuite, and associates the additional icon loading procedure and data value with the family.
  1767. FUNCTION LoadIconCache(theRect: Rect;
  1768.                        align: IconAlignmentType;
  1769.                        transform: IconTransformType;
  1770.                        theIconCache: Handle): OSErr;
  1771. This call allows preflight loading of certain elements of your icon cache. This is handy if you suspect that certain drawing operations may occur at a time not convenient for loading your icon data (e.g., when your resource fork might not be in open chain). LoadIconCache takes the same parameters as PlotIconSuite and uses the same criteria to select the icon to load. The grafPort must be set properly before making this call since it is one of the criteria for determining the icon to load.
  1772. The following four calls are provided to change theData or theProc associated with an icon cache:
  1773. FUNCTION GetIconCacheData(theCache: Handle; 
  1774.                           VAR theData: Ptr): OSErr;
  1775. FUNCTION SetIconCacheData(theCache: Handle; 
  1776.                           theData: Ptr): OSErr;
  1777. FUNCTION GetIconCacheProc(theCache: Handle; 
  1778.                           VAR theProc: IconGetter): OSErr;
  1779. FUNCTION SetIconCacheProc(theCache: Handle; 
  1780.                           theProc: IconGetter): OSErr;
  1781. Plotting Icons Not Part of a Suite
  1782. The next calls are grouped because they are similar. They let you plot an icon to the screen without your creating an icon suite. They are also good if you have a 'cicn' instead of an icon family.
  1783. FUNCTION PlotIconID(theRect: Rect;
  1784.                     align: IconAlignmentType;
  1785.                     transform: IconTransformType;
  1786.                     theResID: INTEGER): OSErr;
  1787. FUNCTION PlotCIconHandle(theRect: Rect;
  1788.                          align: IconAlignmentType;
  1789.                          transform: IconTransformType;
  1790.                          theCIcon: CIconHandle): OSErr;
  1791. FUNCTION PlotIconMethod(theRect: Rect;
  1792.                         align: IconAlignmentType;
  1793.                         transform: IconTransformType;
  1794.                         theMethod: IconGetter;
  1795.                         yourDataPtr: UNIV Ptr): OSErr;
  1796. FUNCTION PlotIconHandle(theRect: Rect;
  1797.                         align: IconAlignmentType;
  1798.                         transform: IconTransformType;
  1799.                         theIcon: Handle): OSErr;
  1800. FUNCTION PlotSICNHandle(theRect: Rect;
  1801.                         align: IconAlignmentType;
  1802.                         transform: IconTransformType;
  1803.                         theSICN: Handle): OSErr;
  1804. All these routines share the following parameters: theRect is the destination rectangle to draw the indicated icon into; align is the alignment method to use if the icon does not fit the rectangle given; transform indicates the desired appearance of the icon on the screen.
  1805. In PlotIconID, the parameter theResID is the resource ID of the family of 'ic' type resources to use. If the correct bit depth or the size required is not defined, the closest-fitting one will be used.
  1806. The PlotCIconHandle parameter theCIcon is a handle that you get to a standard QuickDraw color icon. Unlike PlotCIcon, PlotCIconHandle does not honor the current foreground and background colors. Call GetCIcon to load the icon. Dispose of it when you are done, since they can take up quite a bit of memory.
  1807. PlotIconMethod calls your IconGetter procedure, discussed earlier, to check for the existence of icon data. 
  1808. PlotIconHandle will plot the data from an 'ICN#' or 'ICON' resource from its handle. It is a new version of PlotIcon.
  1809. PlotSICNHandle plots the data of a 'SICN' resource from its handle. Only 'SICN' resources with a single member, or one in which the second member is a mask for the first, will plot correctly.
  1810. All the functions return an error code if things did not go well with the drawing or, in the case of the PlotIconID call, if the indicated icon family could not be used.
  1811. Miscellaneous Calls
  1812. FUNCTION GetLabel(labelNumber: INTEGER;
  1813.                   VAR labelColor: RGBColor;
  1814.                   VAR labelString: Str255): OSErr;
  1815. This call returns the actual color and string used in the label menu of the Finder and the label’s Control Panel. This information is provided in case you wish to include the label text or color when displaying a file’s icon in your application.
  1816. FUNCTION IconSuiteToRgn(theRgn: RgnHandle;
  1817.                         iconRect: Rect;
  1818.                         align: IconAlignmentType;
  1819.                         theIconSuite: Handle): OSErr;
  1820. FUNCTION IconIDToRgn(theRgn: RgnHandle;
  1821.                      iconRect: Rect;
  1822.                      align: IconAlignmentType;
  1823.                      iconID: INTEGER): OSErr;
  1824. FUNCTION IconMethodToRgn(theRgn: RgnHandle;
  1825.                          iconRect: Rect;
  1826.                          align: IconAlignmentType;
  1827.                          theMethod: IconGetter;
  1828.                          yourDataPtr: Ptr): OSErr;
  1829. These routines will create a region from the mask of the icon selected by the iconRect and align values passed. They will allow you to do accurate hit testing and outline dragging of an icon in your application. The RgnHandle must have been previously allocated before you make this call.
  1830. FUNCTION RectInIconSuite(testRect: Rect;
  1831.                          iconRect: Rect;
  1832.                          align: IconAlignmentType;
  1833.                          theIconSuite: Handle): BOOLEAN;
  1834. FUNCTION RectInIconID(testRect: Rect;
  1835.                       iconRect: Rect;
  1836.                       align: IconAlignmentType;
  1837.                       iconID: INTEGER): BOOLEAN;
  1838. FUNCTION RectInIconMethod(testRect: Rect;
  1839.                           iconRect: Rect;
  1840.                           align: IconAlignmentType;
  1841.                           theMethod: IconGetter;
  1842.                           yourDataPtr: Ptr): BOOLEAN;
  1843. FUNCTION PtInIconSuite(testPt: Point;
  1844.                        iconRect: Rect;
  1845.                        align: IconAlignmentType;
  1846.                        theIconSuite: Handle): BOOLEAN;
  1847. FUNCTION PtInIconID(testPt: Point;
  1848.                     iconRect: Rect;
  1849.                     align: IconAlignmentType;
  1850.                     iconID: INTEGER): BOOLEAN;
  1851. FUNCTION PtInIconMethod(testPt: Point;
  1852.                         iconRect: Rect;
  1853.                         align: IconAlignmentType;
  1854.                         theMethod: IconGetter;
  1855.                         yourDataPtr: Ptr): BOOLEAN;
  1856. These calls hit test the passed Point or Rect against the icon indicated. The parameters iconRect and align, and the grafPort should be the same as when the icon was last drawn. The functions return true if the point is in the icon mask or if the rectangle intersects the icon mask.
  1857. Error Codes
  1858. The Icon Utilities will pass back any errors encountered during execution, so you can expect to see Memory Manager, Resource Manager, and other normal errors.
  1859. There is one error code defined specifically for the Icon Utilities routines that may be returned by the Icon plotting routines.
  1860. { Pascal }
  1861. CONST
  1862.     noMaskFound = -1000;
  1863. END;
  1864. /* C */
  1865. #define noMaskFound    -1000
  1866. This error will be returned if the Icon Utilities package could not find or create a mask for the icon family.  The Icon Utilities will use the correct mask for each icon size, if one is available.  If no mask for a specific size is available, a mask will be created from any mask in the family, but if there are no 1 bit images and no mask in the family, plotting calls will fail with this error.
  1867. Type(def)s and Glue for Pascal and C
  1868. The Pascal and C interfaces are provided here to copy and paste since the current MPW standard interface files do not contain the glue for these calls. Electronic versions of this note are on AppleLink (Developer Support: Developer Services: Technical Documentation: Macintosh Technical Notes: Imaging: Graphics: Icon Drawing in 7.sit (Stuffit)) and the Developer CD (Technical Documentation: Macintosh Technical Notes: Imaging: Graphics: Icon Drawing in 7).
  1869. MPW C, Pascal, and Assembler files also have been submitted to AppleLink and the Developer CD, but their paths were not known when this note was written.
  1870. { Pascal Types }
  1871. IconAction         =  ProcPtr;  {FUNCTION IconAction(theType: ResType;
  1872.                                                      VAR theIcon: Handle;
  1873.                                                      yourDataPtr: Ptr): OSErr;}
  1874. IconGetter         =  ProcPtr;  {FUNCTION IconGetter(theType: ResType;
  1875.                                                      yourDataPtr: Ptr): Handle;}
  1876. IconSelectorValue  =  LONGINT;
  1877. IconAlignmentType  =  INTEGER;
  1878. IconTransformType  =  INTEGER;
  1879. { Pascal Glue }
  1880. FUNCTION PlotIconID(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  1881.                     theResID: INTEGER): OSErr;
  1882.          INLINE  $303C, $0500, $ABC9;
  1883. FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  1884.          INLINE  $303C, $0207, $ABC9;
  1885. FUNCTION AddIconToSuite(theIconData: Handle; theSuite: Handle; theType: ResType): OSErr;
  1886.          INLINE  $303C, $0608, $ABC9;
  1887. FUNCTION GetIconFromSuite(VAR theIconData: Handle; theSuite: Handle; theType: ResType): OSErr;
  1888.          INLINE  $303C, $0609, $ABC9;
  1889. FUNCTION ForEachIconDo(theSuite: Handle; selector: IconSelectorValue; action: IconAction;
  1890.                        yourDataPtr: Ptr): OSErr;
  1891.          INLINE  $303C, $060A, $ABC9;
  1892. FUNCTION GetIconSuite(VAR theIconSuite: Handle; theResID: INTEGER;
  1893.                       selector: IconSelectorValue): OSErr;
  1894.          INLINE  $303C, $0501, $ABC9;
  1895. FUNCTION DisposeIconSuite(theIconSuite: Handle; disposeData: BOOLEAN): OSErr;
  1896.          INLINE  $303C, $0302, $ABC9;
  1897. FUNCTION PlotIconSuite(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  1898.                        theIconSuite: Handle): OSErr;
  1899.         INLINE  $303C, $0603, $ABC9;
  1900. FUNCTION MakeIconCache(VAR theHandle: Handle; makeIcon: IconGetter;
  1901.                        yourDataPtr: UNIV Ptr): OSErr;
  1902.          INLINE  $303C, $0604, $ABC9;
  1903. FUNCTION LoadIconCache(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  1904.                        theIconCache: Handle): OSErr;
  1905.          INLINE  $303C, $0606, $ABC9;
  1906. FUNCTION PlotIconMethod(theRect: Rect; align: IconAlignmentType;
  1907.                         transform: IconTransformType; theMethod: IconGetter;
  1908.                         yourDataPtr: UNIV Ptr): OSErr; 
  1909.          INLINE  $303C, $0805, $ABC9;
  1910. FUNCTION GetLabel(labelNumber: INTEGER; VAR labelColor: RGBColor;
  1911.                   VAR labelString: Str255): OSErr;
  1912.          INLINE  $303C, $050B, $ABC9;
  1913. FUNCTION PtInIconID(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  1914.                     iconID: INTEGER): BOOLEAN;
  1915.          INLINE  $303C, $060D, $ABC9;
  1916. FUNCTION PtInIconSuite(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  1917.                        theIconSuite: Handle): BOOLEAN;
  1918.          INLINE  $303C, $070E, $ABC9;
  1919. FUNCTION PtInIconMethod(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  1920.                         theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;
  1921.          INLINE  $303C, $090F, $ABC9;
  1922. FUNCTION RectInIconID(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  1923.                       iconID: INTEGER): BOOLEAN;
  1924.          INLINE  $303C, $0610, $ABC9;
  1925. FUNCTION RectInIconSuite(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  1926.                          theIconSuite: Handle): BOOLEAN;
  1927.          INLINE  $303C, $0711, $ABC9;
  1928. FUNCTION RectInIconMethod(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  1929.                           theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;
  1930.          INLINE  $303C, $0912, $ABC9;
  1931. FUNCTION IconIDToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  1932.                      iconID: INTEGER): OSErr;
  1933.          INLINE  $303C, $0913, $ABC9;
  1934. FUNCTION IconSuiteToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  1935.                         theIconSuite: Handle): OSErr;
  1936.          INLINE  $303C, $0914, $ABC9;
  1937. FUNCTION IconMethodToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  1938.                          theMethod: IconGetter; yourDataPtr: Ptr): OSErr;
  1939.          INLINE  $303C, $0915, $ABC9;
  1940. FUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  1941.          INLINE  $303C, $0316, $ABC9;
  1942. FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  1943.          INLINE  $303C, $0217, $ABC9;
  1944. FUNCTION GetIconCacheData(theCache: Handle; VAR theData: Ptr): OSErr;
  1945.          INLINE  $303C, $0419, $ABC9;
  1946. FUNCTION SetIconCacheData(theCache: Handle; theData: Ptr): OSErr;
  1947.          INLINE  $303C, $041A, $ABC9;
  1948. FUNCTION GetIconCacheProc(theCache: Handle; VAR theProc: IconGetter): OSErr;
  1949.          INLINE  $303C, $041B, $ABC9;
  1950. FUNCTION SetIconCacheProc(theCache: Handle; theProc: IconGetter): OSErr;
  1951.          INLINE  $303C, $041C, $ABC9;
  1952. FUNCTION PlotIconHandle(theRect: Rect; align: IconAlignmentType;
  1953.                         transform: IconTransformType; theIcon: Handle): OSErr;
  1954.          INLINE  $303C, $061D, $ABC9;
  1955. FUNCTION PlotSICNHandle(theRect: Rect; align: IconAlignmentType;
  1956.                         transform: IconTransformType; theSICN: Handle): OSErr;
  1957.          INLINE  $303C, $061E, $ABC9;
  1958. FUNCTION PlotCIconHandle(theRect: Rect; align: IconAlignmentType;
  1959.                          transform: IconTransformType; theCIcon: CIconHandle): OSErr;
  1960.          INLINE  $303C, $061F, $ABC9;
  1961. /* C Typedefs */
  1962. typedef pascal OSErr   (*IconAction)(ResType theType, Handle *theIcon, void *yourDataPtr);
  1963. typedef pascal Handle  (*IconGetter)(ResType theType, void *yourDataPtr);
  1964. typedef unsigned long  IconSelectorValue;
  1965. typedef short          IconAlignmentType;
  1966. typedef short          IconTransformType;
  1967. /* C Glue */
  1968. pascal OSErr PlotIconID(const Rect *theRect, IconAlignmentType align,
  1969.                         IconTransformType transform, short theResID)
  1970.        =  {0x303C, 0x0500, 0xABC9};
  1971. pascal OSErr NewIconSuite(Handle *theIconSuite)
  1972.        =  {0x303C, 0x0207, 0xABC9};
  1973. pascal OSErr AddIconToSuite(Handle theIconData, Handle theSuite, ResType theType)
  1974.        =  {0x303C, 0x0608, 0xABC9};
  1975. pascal OSErr GetIconFromSuite(Handle *theIconData, Handle theSuite, ResType theType)
  1976.        =  {0x303C, 0x0609, 0xABC9};
  1977. pascal OSErr ForEachIconDo(Handle theSuite, IconSelectorValue selector, IconAction action,
  1978.                            void *yourDataPtr)
  1979.        =  {0x303C, 0x080A, 0xABC9};
  1980. pascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, IconSelectorValue selector)
  1981.        =  {0x303C, 0x0501, 0xABC9};
  1982. pascal OSErr DisposeIconSuite(Handle theIconSuite, Boolean disposeData)
  1983.        =  {0x303C, 0x0302, 0xABC9};
  1984. pascal OSErr PlotIconSuite(const Rect *theRect, IconAlignmentType align,
  1985.                            IconTransformType transform, Handle theIconSuite)
  1986.        =  {0x303C, 0x0603, 0xABC9};
  1987. pascal OSErr MakeIconCache(Handle *theHandle, IconGetter makeIcon, void *yourDataPtr)
  1988.        =  {0x303C, 0x0604, 0xABC9};
  1989. pascal OSErr LoadIconCache(const Rect *theRect, IconAlignmentType align,
  1990.                            IconTransformType transform, Handle theIconCache)
  1991.        =  {0x303C, 0x0606, 0xABC9};
  1992. pascal OSErr PlotIconMethod(const Rect *theRect, IconAlignmentType align,
  1993.                             IconTransformType transform, IconGetter theMethod,
  1994.                             void *yourDataPtr)
  1995.        =  {0x303C, 0x0805, 0xABC9};
  1996. pascal OSErr GetLabel(short labelNumber, RGBColor *labelColor, Str255 labelString)
  1997.        =  {0x303c, 0x050B, 0xABC9};
  1998. pascal Boolean PtInIconID(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  1999.                           short iconID)
  2000.        =  {0x303c, 0x060D, 0xABC9};
  2001. pascal Boolean PtInIconSuite(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  2002.                              Handle theIconSuite)
  2003.        =  {0x303c, 0x070E, 0xABC9};
  2004. pascal Boolean PtInIconMethod(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  2005.                               IconGetter theMethod, void *yourDataPtr)
  2006.        =  {0x303c, 0x090F, 0xABC9};
  2007. pascal Boolean RectInIconID(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  2008.                             short iconID)
  2009.        =  {0x303c, 0x0610, 0xABC9};
  2010. pascal Boolean RectInIconSuite(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  2011.                                Handle theIconSuite)
  2012.        =  {0x303c, 0x0711, 0xABC9};
  2013. pascal Boolean RectInIconMethod(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  2014.                                 IconGetter theMethod, void *yourDataPtr)
  2015.        =  {0x303c, 0x0912, 0xABC9};
  2016. pascal OSErr IconIDToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  2017.                          short iconID)
  2018.        =  {0x303c, 0x0613, 0xABC9};
  2019. pascal OSErr IconSuiteToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  2020.                             Handle theIconSuite)
  2021.        =  {0x303c, 0x0714, 0xABC9};
  2022. pascal OSErr IconMethodToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  2023.                              IconGetter theMethod, void *yourDataPtr)
  2024.        =  {0x303c, 0x0915, 0xABC9};
  2025. pascal OSErr SetSuiteLabel(Handle theSuite, short theLabel)
  2026.        =  {0x303C, 0x0316, 0xABC9};
  2027. pascal short GetSuiteLabel(Handle theSuite)
  2028.        =  {0x303C, 0x0217, 0xABC9};
  2029. pascal OSErr GetIconCacheData(Handle theCache, void **theData)
  2030.        =  {0x303C, 0x0419, 0xABC9};
  2031. pascal OSErr SetIconCacheData(Handle theCache, void *theData)
  2032.        =  {0x303C, 0x041A, 0xABC9};
  2033. pascal OSErr GetIconCacheProc(Handle theCache, IconGetter *theProc)
  2034.        =  {0x303C, 0x041B, 0xABC9};
  2035. pascal OSErr SetIconCacheProc(Handle theCache, IconGetter theProc)
  2036.        =  {0x303C, 0x041C, 0xABC9};
  2037. pascal OSErr PlotIconHandle(const Rect *theRect, IconAlignmentType align,
  2038.                             IconTransformType transform, Handle theIcon)
  2039.        =  {0x303C, 0x061D, 0xABC9};
  2040. pascal OSErr PlotSICNHandle(const Rect *theRect, IconAlignmentType align,
  2041.                             IconTransformType transform, Handle theSICN)
  2042.        =  {0x303C, 0x061E, 0xABC9};
  2043. pascal OSErr PlotCIconHandle(const Rect *theRect, IconAlignmentType align,
  2044.                              IconTransformType transform, CIconHandle theCIcon)
  2045.        =  {0x303C, 0x061F, 0xABC9};
  2046. Further Reference:
  2047. •    Inside Macintosh, Volume V, QuickDraw chapter
  2048. •    Inside Macintosh, Volume VI, Finder Interface chapter
  2049. Displaying Large PICT Files 
  2050. Imaging    M.IM.LargePict
  2051. Revised by:        March 1988
  2052. Written by:    Rick Blair     July 1987
  2053. Now that we have scanners and other massive-picture producing types of applications, there is a need to address the problem of how to display a PICT format object that is bigger than a current PICT resource is allowed to be. Note that this technique applies equally well to version 1 and version 2 (word-opcode) pictures as produced by the Macintosh II.
  2054. Future Compatibility
  2055. Think of the handle returned by a GetResource('PICT',ID) as a “handle” in the more general sense of being an abstract “tag”—something that the ROM routines can use to draw the picture with. Don’t assume that the entire picture has been read into memory or that you can directly read any bytes beyond the basic Picture record structure (picSize followed by picFrame). Someday we may provide a mechanism for the resource to be disk- instead of memory-based. The QuickDraw bottleneck procedures will know how to get data from and put data into the pictures in any case.
  2056. Spooling from a PICT file
  2057. In order to display pictures of arbitrary size, your application should be able to import a QuickDraw picture from a file of type PICT. This is the file produced by a “Save as…” from MacDraw with the PICT option selected.
  2058. What follows is a small program fragment that demonstrates how to spool in a picture from [the data fork of] a PICT file. The picture can be larger than the historical 32K resource size. See technical note #88 if you are unfamiliar with the Signal mechanism. We assume that a CatchSignals has been done before GetandDrawPICTFile is called.
  2059. MPW Pascal Example
  2060.     {the following variable must be at the top level}
  2061.     VAR
  2062.        globalRef   : INTEGER;      {refNum of the file to read from}
  2063.     {the following procedure must be at the top level}
  2064.     PROCEDURE GetPICTData(dataPtr: Ptr; byteCount: INTEGER);
  2065.     {replacement for the QuickDraw bottleneck routine}
  2066.        VAR
  2067.           err         : OSErr;
  2068.           longCount   : LONGINT;
  2069.        BEGIN
  2070.           longCount := byteCount;
  2071.           err := FSRead(globalRef,longCount,dataPtr);
  2072.           {can't check for an error because we don't know how to handle it}
  2073.        END;
  2074.     CONST
  2075.        abortPICT    = 128;         {error code if DrawPicture aborted}
  2076.     PROCEDURE GetDrawPICTFile;     {read in a PICT FILE selected by the user}
  2077.        VAR
  2078.           wher        : Point;     {where to display dialog}
  2079.           reply       : SFReply;   {reply record}
  2080.           myFileTypes : SFTypeList; {more Standard FILE goodies}
  2081.           numFileTypes: INTEGER;
  2082.           savedProcs  : QDProcsPtr;
  2083.           myProcs     : QDProcs;   {use CQDProcs for a color window}
  2084.           myPicture   : PicHandle; {we need a picture handle for DrawPicture}
  2085.           longCount   : LONGINT;
  2086.           myEOF       : LONGINT;
  2087.           myFilePos   : LONGINT;
  2088.        BEGIN
  2089.           wher.h := 20;
  2090.           wher.v := 20;
  2091.           numFileTypes := 1;       {display PICT files}
  2092.           myFileTypes[0] := 'PICT';
  2093.           SFGetFile(wher,'',NIL,numFileTypes,myFileTypes,NIL,reply);
  2094.           IF reply.good THEN BEGIN
  2095.              SetStdProcs(myProcs); {use SetStdCProcs for a CGrafPort}
  2096.              myProcs.getPicProc := @GetPICTData;
  2097.              savedProcs := thePort^.grafProcs; {set the grafProcs to ours}
  2098.              thePort^.grafProcs := @myProcs;
  2099.              myPicture := PicHandle(NewHandle(SizeOf(myPicture)));
  2100.              Signal(FSOpen(reply.fname,reply.vRefNum,globalRef));
  2101.              Signal(GetEOF(globalRef,myEOF)); {get EOF for later check}
  2102.              Signal(SetFPos(globalRef,fsFromStart,512)); {skip header}
  2103.              {read in the (obsolete) size word and the picFrame}
  2104.              longCount := SizeOf(myPicture);
  2105.              Signal(FSRead(globalRef,longCount,Ptr(myPicture^)));
  2106.              DrawPicture(myPicture,myPicture^^.picFrame); {draw the picture}
  2107.              Signal(GetFPos(globalRef,filePos)); {get position for check}
  2108.              Signal(FSClose(globalRef));
  2109.              DisposHandle(Handle(myPicture));
  2110.              thePort^.grafProcs := savedProcs; {restore the procs}
  2111.              {Check for errors. If there wasn't enough room,}
  2112.              {DrawPicture will abort; the FILE position mark}
  2113.              {won't be at the end of the FILE.}
  2114.              IF filePos <> myEOF THEN Signal(abortPICT);
  2115.           END; {IF reply.good}
  2116.        END; {GetDrawPICTFile}
  2117. MPW C Example
  2118. /*replacement for the QuickDraw bottleneck routine*/
  2119. pascal void GetPICTData(dataPtr,byteCount)
  2120. Ptr            dataPtr; 
  2121. short            byteCount;
  2122. { /* GetPICTData */
  2123.     OSErr            err;
  2124.     long            longCount;
  2125.     longCount = byteCount;
  2126.     err = FSRead(globalRef,&longCount,dataPtr);
  2127.     /*can't check for an error because we don't know how to handle it*/
  2128. } /* GetPICTData */
  2129. /*error code if DrawPicture aborted*/
  2130. #define       abortPICT     128         
  2131. OSErr GetDrawPICTFile()        /*read in a PICT FILE selected by the user*/
  2132. {    /* GetDrawPICTFile */   
  2133.     Point         wher;         /*where to display dialog*/
  2134.     SFReply    reply;      /*reply record*/
  2135.     SFTypeList    myFileTypes;    /*more Standard FILE goodies*/
  2136.     short         numFileTypes;
  2137.     OSErr        err;
  2138.     QDProcsPtr    savedProcs;
  2139.     QDProcs    myProcs;    /*use CQDProcs for a color window*/
  2140.     PicHandle    myPicture;    /*we need a picture handle for DrawPicture*/
  2141.     long        longCount,myEOF,filePos;
  2142.           wher.h = 20;
  2143.           wher.v = 20;
  2144.           numFileTypes = 1;                   /*display PICT files*/
  2145.           myFileTypes[0] = 'PICT';
  2146.           SFGetFile(wher,'',nil,numFileTypes,myFileTypes,nil,&reply);
  2147.           if (reply.good)  
  2148.         {
  2149.             SetStdProcs(&myProcs);
  2150.             /*use SetStdCProcs for a CGrafPort*/
  2151.                  myProcs.getPicProc = GetPICTData;
  2152.                  savedProcs = (*qd.thePort).grafProcs;
  2153.             /*set the grafProcs to ours*/
  2154.                  (*qd.thePort).grafProcs = &myProcs;
  2155.                  myPicture = (PicHandle)NewHandle(sizeof(Picture));
  2156.             err = FSOpen(&reply.fName,reply.vRefNum,&globalRef);
  2157.             if (err != noErr) return err;
  2158.                   err = GetEOF(globalRef,&myEOF);
  2159.             /*get EOF for later check*/
  2160.             if (err != noErr) return err;
  2161.             err = SetFPos(globalRef,fsFromStart,512);/*skip header*/
  2162.                  if (err != noErr) return err;
  2163.                  /*read in the (obsolete) size word and the picFrame*/
  2164.                  longCount = sizeof(Picture);
  2165.                  err = FSRead(globalRef,&longCount,(Ptr)*myPicture);
  2166.                  if (err != noErr) return err;
  2167.                  DrawPicture(myPicture,&(**myPicture).picFrame); /*draw                                 the picture*/
  2168.             err = GetFPos(globalRef,&filePos);/*get position for                                 check*/
  2169.                  if (err != noErr) return err;
  2170.                  err = FSClose(globalRef);
  2171.                  if (err != noErr) return err;
  2172.                  DisposHandle((Handle)myPicture);
  2173.                  (*qd.thePort).grafProcs = savedProcs;/*restore the                                 procs*/
  2174.                  /*Check for errors. if there wasn't enough room,*/
  2175.                  /*DrawPicture will abort; the FILE position mark*/
  2176.                  /*won't be at the end of the FILE.*/
  2177.             if (filePos != myEOF)  return abortPICT;
  2178.             else return noErr;
  2179.           } /*if (reply.good) */
  2180. }     /* GetDrawPICTFile */
  2181. More on Picture Compatibility
  2182. Many applications already support PICT resources larger than 32K. The 128K ROMs (and later) allow pictures as large as memory (or spooling) will accommodate. This was made possible by having QuickDraw ignore the size word and simply read the picture until the end-of-picture opcode was reached.
  2183. For maximum safety and convenience, let QuickDraw generate and interpret your pictures.
  2184. While Apple has provided you with the data formats that allow you to read or write picture data directly, we recommend that you always let DrawPicture or OpenPicture and ClosePicture process the opcodes.
  2185. One reason to read a picture directly by scanning the opcodes would be to disassemble it to, for example, extract a Color QuickDraw pixel map to save off in a private data structure. This shouldn’t normally be necessary.
  2186. If you do look at the picture data be sure and check the version information. You may want to put up an alert in your application that indicates to the user when a picture was created using a later version of the picture format than your application recognizes, letting them know that some elements of the picture cannot be displayed. If the version information indicates a QuickDraw picture version later than the one recognized by your application, your program should skip over the new opcodes and only attempt to parse the ones it knows.
  2187. As with reading picture data directly, it is best to use QuickDraw to create data in the PICT format. If you do need to create PICT format data directly, it is essential that you use the latest opcode specifications and that you thoroughly test the data produced on both color and black and white Macintosh machines. Contact Macintosh Developer Technical Support if you are not sure that you have the latest specifications.
  2188. Apple does not guarantee that a picture which wasn’t produced by QuickDraw will work.
  2189. Further Reference:
  2190. •    QuickDraw
  2191. •    Technical Note M.IM.PictureOpcodes —
  2192.         Internal Picture Format
  2193. •    Technical Note M.PT.Signals —
  2194.         Signals
  2195. LaserWriter Utility Q&As
  2196. Imaging    M.IM.LWUtil.Q&As
  2197. Revised by:    Developer Support Center    October 1992
  2198. Written by:    Developer Support Center    October 1990
  2199. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  2200. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  2201. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  2202. SCSI drive format for LaserWriter II NTX with Rev. 3 ROMs
  2203. Written:    5/3/91
  2204. Last reviewed:    6/26/91
  2205. What could be causing intermittent PostScript errors from a LaserWriter II NTX with an SCSI hard disk mounted after installing the Rev 3 ROM upgrade?
  2206. ___
  2207. The LaserWriter II NTX with Rev 3 ROMs does not work properly with a hard disk formatted with the LaserWriter Font Utility 1.x. You need to reformat the disk and copy the fonts back onto the hard disk using the LaserWriter Font Utility 2.0.2. Unfortunately, there is no way to make this procedure easier.
  2208. LaserWriter Font Utility copies Postscript file to printer
  2209. Written:    9/23/91
  2210. Last reviewed:    10/8/91
  2211. Is there a utility that will send a PostScript file from disk to the LaserWriter?
  2212. ___
  2213. The LaserWriter Font Utility handles this job and is part of the System 7 disk set. On the System 7 Golden Master CD, the path is System 7.0: System Software 7.0: Installer Version: Tidbits folder.
  2214. Drawing Into an Off-Screen Bitmap
  2215. Imaging    M.IM.OffscreenBitMap
  2216. Revised by:    Jon Zap & Forrest Tanaka    June 1990
  2217. Written by:    Jim Friedlander & Ginger Jernigan    July 1985
  2218. This Technical Note provides an example of creating an off-screen bitmap, drawing to it, and then copying from it to the screen.
  2219. Changes since April 1990:  Clarified the section on window updates with off-screen bitmaps to explicitly limit these updates to your own windows.
  2220. The following is an example of creating and drawing to an off-screen bitmap, then copying from it to an on-screen window.  We supply this example in both MPW Pascal and C.
  2221. MPW Pascal
  2222. First, let’s look at a general purpose function to create an off-screen bitmap.  This function creates the GrafPort on the heap.  You could also create it on the stack and pass the uninitialized structure to a function similar to this one.
  2223. FUNCTION CreateOffscreenBitMap(VAR newOffscreen:GrafPtr; inBounds:Rect) : BOOLEAN;
  2224. VAR
  2225.   savePort  : GrafPtr;
  2226.   newPort   : GrafPtr;
  2227. BEGIN
  2228.   GetPort(savePort);        {need this to restore thePort after OpenPort changes it}
  2229.   newPort := GrafPtr(NewPtr(sizeof(GrafPort)));    {allocate the GrafPort}
  2230.   IF MemError <> noErr THEN BEGIN
  2231.     CreateOffscreenBitMap := false;                {failed to allocate it}
  2232.     EXIT(CreateOffscreenBitMap);
  2233.   END;
  2234.   {
  2235.   the OpenPort call does the following . . . 
  2236.     allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  2237.     sets portBits to screenBits
  2238.     sets portRect to screenBits.bounds
  2239.     etc. (see IM I-163,164)
  2240.     side effect: does a SetPort(offScreen)
  2241.   }
  2242.   OpenPort(newPort);
  2243.   {make bitmap exactly the size of the bounds that caller supplied}
  2244.   WITH newPort^ DO BEGIN {portRect, clipRgn, and visRgn are in newPort}
  2245.     portRect := inBounds;
  2246.     RectRgn(clipRgn, inBounds);        {avoid wide-open clipRgn, to be safe}
  2247.     RectRgn(visRgn, inBounds);         {in case inBounds is > screen bounds}
  2248.   END;
  2249.   WITH newPort^.portBits DO BEGIN       {baseAddr, rowBytes and bounds are in newPort}
  2250.     bounds := inBounds;
  2251.     {rowBytes is size of row  It must be rounded up to even number of bytes}
  2252.     rowBytes := ((inBounds.right - inBounds.left + 15) DIV 16) * 2;
  2253.     {number of bytes in BitMap is rowBytes * number of rows}
  2254.     {see note at end of Technical Note about using _NewHandle rather than _NewPtr}
  2255.     baseAddr := NewPtr(rowBytes * LONGINT(inBounds.bottom - inBounds.top));
  2256.   END;
  2257.   IF MemError <> noErr THEN BEGIN    {see if we had enough room for the bits}
  2258.     SetPort(savePort);
  2259.     ClosePort(newPort);              { dump the visRgn and clipRgn }
  2260.     DisposPtr(Ptr(newPort));         { dump the GrafPort}
  2261.     CreateOffscreenBitMap := false;
  2262.   END
  2263.   ELSE BEGIN
  2264.     { since the bits are just memory, let's erase them before we start }
  2265.     EraseRect(inBounds);            {OpenPort did a SetPort(newPort)}
  2266.     newOffscreen := newPort;
  2267.     SetPort(savePort);
  2268.     CreateOffscreenBitMap := true;
  2269.   END;
  2270. END;
  2271. Here is the procedure to get rid of an off-screen bitmap created by the previous function:
  2272. PROCEDURE DestroyOffscreenBitMap(oldOffscreen : GrafPtr);
  2273. BEGIN
  2274.   ClosePort(oldOffscreen);                       { dump the visRgn and clipRgn }
  2275.   DisposPtr(oldOffscreen^.portBits.baseAddr);    { dump the bits }
  2276.   DisposPtr(Ptr(oldOffscreen));                  { dump the port }
  2277. END;
  2278. Now that you know how to create and destroy an off-screen bitmap, let’s go through the motions of using one.  First, let’s define a few things to make the _NewWindow call a little clearer.
  2279. CONST
  2280.   kIsVisible   = true;
  2281.   kNoGoAway    = false;
  2282.   kMakeFrontWindow = -1;
  2283.   myString     = 'The EYE';  {string to display}
  2284. Here’s the body of the test code:
  2285. VAR
  2286.   offscreen : GrafPtr;    {our off-screen bitmap}
  2287.   ovalRect  : Rect;       {used for example drawing}
  2288.   myWBounds : Rect;       {for creating window}
  2289.   OSRect    : Rect;       {portRect and bounds for off-screen bitmap}
  2290.   myWindow  : WindowPtr;
  2291. BEGIN
  2292.   InitToolbox;                       {exercise left to the reader}
  2293.   myWBounds := screenBits.bounds;    { size of main screen }
  2294.   InsetRect(myWBounds, 50,50);       { make it fit better }
  2295.   myWindow := NewWindow(NIL, myWBounds, 'Test Window', kIsVisible,
  2296.                         noGrowDocProc, WindowPtr(kMakeFrontWindow), kNoGoAway, 0);
  2297.   IF NOT CreateOffscreenBitMap(offscreen,myWindow^.portRect) THEN BEGIN 
  2298.     SysBeep(1);
  2299.     ExitToShell;
  2300.   END;
  2301.   { Example drawing to our off-screen bitmap }
  2302.   SetPort(offscreen);
  2303.   OSRect := offscreen^.portRect;    { offscreen bitmap's local coordinate rect }
  2304.   ovalRect := OSRect;
  2305.   FillOval(ovalRect, black);
  2306.   InsetRect(ovalRect, 1, 20);
  2307.   FillOval(ovalRect, white);
  2308.   InsetRect(ovalRect, 40, 1);
  2309.   FillOval(ovalRect, black);
  2310.   WITH ovalRect DO
  2311.     MoveTo((left+right-StringWidth(myString)) DIV 2, (top+bottom-12) DIV 2);
  2312.   TextMode(srcXor);
  2313.   DrawString(myString);
  2314.   { copy from the off-screen bitmap to the on-screen window.  Note that in this
  2315.   case the source and destination rects are the same size and both cover the
  2316.   entire area.  These rects are allowed to be portions of the source and/or
  2317.   destination and do not have to be the same size.  If they are not the same size
  2318.   then _CopyBits scales the image accordingly
  2319.   }
  2320.   SetPort(myWindow);
  2321.   CopyBits(offscreen^.portBits, myWindow^.portBits,
  2322.            offscreen^.portRect, myWindow^.portRect, srcCopy, NIL);
  2323.   DestroyOffscreenBitMap(offscreen);    {remove the evidence}
  2324.   WHILE NOT Button DO;                  {give user a chance to see the results}
  2325. END.
  2326. MPW C
  2327. First, let’s look at a general purpose function to create an off-screen bitmap.  This function creates the GrafPort on the heap.  You could also create it on the stack and pass the uninitialized structure to a function similar to this one.
  2328. Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)
  2329. {
  2330.   GrafPtr savePort;
  2331.   GrafPtr newPort;
  2332.   GetPort(&savePort);    /* need this to restore thePort after OpenPort */
  2333.   newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */
  2334.   if (MemError() != noErr)
  2335.     return false;                 /* failed to allocate the off-screen port */
  2336.   /*
  2337.   the call to OpenPort does the following . . . 
  2338.     allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  2339.     sets portBits to screenBits
  2340.     sets portRect to screenBits.bounds
  2341.     etc. (see IM I-163,164)
  2342.     side effect: does a SetPort(&offScreen)
  2343.   */
  2344.   OpenPort(newPort);
  2345.   /* make bitmap the size of the bounds that caller supplied */
  2346.   newPort->portRect = *inBounds;
  2347.   newPort->portBits.bounds = *inBounds;
  2348.   RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */
  2349.   RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */
  2350.   /* rowBytes is size of row, it must be rounded up to an even number of bytes */
  2351.   newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;
  2352.   /* number of bytes in BitMap is rowBytes * number of rows */
  2353.   /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr */
  2354.   newPort->portBits.baseAddr =
  2355.            NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds->top));
  2356.   if (MemError()!=noErr) {   /* check to see if we had enough room for the bits */
  2357.     SetPort(savePort);
  2358.     ClosePort(newPort);      /* dump the visRgn and clipRgn */
  2359.     DisposPtr((Ptr)newPort); /* dump the GrafPort */
  2360.     return false;            /* tell caller we failed */
  2361.     }
  2362.   /* since the bits are just memory, let's clear them before we start */
  2363.   EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */
  2364.   *newOffscreen = newPort;
  2365.   SetPort(savePort);
  2366.   return true;               /* tell caller we succeeded! */
  2367. }
  2368. Here is the function to get rid of an off-screen bitmap created by the previous function:
  2369. void DestroyOffscreenBitMap(GrafPtr oldOffscreen)
  2370. {
  2371.   ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */
  2372.   DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */
  2373.   DisposPtr((Ptr)oldOffscreen);                  /* dump the port */
  2374. }
  2375. Now that you know how to create and destroy an off-screen bitmap, let’s go through the motions of using one.  First, let’s define a few things to make the _NewWindow call a little clearer.
  2376. #define kIsVisible true
  2377. #define kNoGoAway false
  2378. #define kNoWindowStorage 0L
  2379. #define kFrontWindow ((WindowPtr) -1L)
  2380. Here’s the body of the test code:
  2381. main()
  2382. {
  2383.   char* myString = "\pThe EYE";  /* string to display */
  2384.   GrafPtr   offscreen;           /* our off-screen bitmap */
  2385.   Rect      ovalRect;            /* used for example drawing */
  2386.   Rect      myWBounds;           /* for creating window */
  2387.   Rect      OSRect;              /* portRect and bounds for off-screen bitmap*/
  2388.   WindowPtr myWindow;
  2389.   InitToolbox();                 /* exercise for the reader */
  2390.   myWBounds = qd.screenBits.bounds;  /* size of main screen */
  2391.   InsetRect(&myWBounds, 50,50);  /* make it fit better */
  2392.   myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window", kIsVisible,
  2393.                        noGrowDocProc, kFrontWindow, kNoGoAway, 0);
  2394.   if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {
  2395.     SysBeep(1);
  2396.     ExitToShell();
  2397.     }
  2398.   /* Example drawing to our off-screen bitmap*/
  2399.   SetPort(offscreen);
  2400.   OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect */
  2401.   ovalRect = OSRect;
  2402.   FillOval(&ovalRect, qd.black);
  2403.   InsetRect(&ovalRect, 1, 20);
  2404.   FillOval(&ovalRect, qd.white);
  2405.   InsetRect(&ovalRect, 40, 1);
  2406.   FillOval(&ovalRect, qd.black);
  2407.   MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,
  2408.          (ovalRect.top + ovalRect.bottom - 12) >> 1);
  2409.   TextMode(srcXor);
  2410.   DrawString(myString);
  2411.   /* copy from the off-screen bitmap to the on-screen window.  Note that in this
  2412.   case the source and destination rects are the same size and both cover the
  2413.   entire area.  These rects are allowed to be portions of the source and/or
  2414.   destination and do not have to be the same size.  If they are not the same size
  2415.   then _CopyBits scales the image accordingly.
  2416.   */
  2417.   SetPort(myWindow);
  2418.   CopyBits(&offscreen->portBits, &(*myWindow).portBits,
  2419.            &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);
  2420.   DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */
  2421.   while (!Button());     /* give user a chance to see our work of art */
  2422. }
  2423. Comments
  2424. In the example code, the bits of the BitMap structure, which are pointed to by the baseAddr field, are allocated by a _NewPtr call.  If your off-screen bitmap is close to the size of the screen, then the amount of memory needed for the bits can be quite large (on the order of 20K for the Macintosh SE or 128K for a large screen).  This is quite a lot of memory to lock down in your heap and it can easily lead to fragmentation if you intend to keep the off-screen bitmap around for any length of time.  One alternative that lessens this problem is to get the bits via _NewHandle so the Memory Manager can move them when necessary.  To implement this approach, you need to keep the handle separate from the GrafPort (for example, in a structure that combines a GrafPort and a Handle).  When you want to use the off-screen bitmap you would then lock the handle and put the dereferenced handle into the baseAddr field.  When you are not using the off-screen bitmap you can then unlock it.
  2425. This example does not demonstrate one of the more typical uses of off-screen bitmaps, which is to preserve the contents of windows so that after a temporary window or dialog box obscures part of your windows and is then dismissed, you can quickly handle the resulting update events without recreating all of the intermediate drawing commands.
  2426. Make sure you only restore the pixels within the content regions of your own windows in case the temporary window partly obscures windows belonging to other applications or to the desktop.  Another application could change the contents of its windows while they are behind your temporary window, so you cannot simply restore all the pixels that were behind the temporary window because that would restore the old contents of the other application’s windows.  Instead, you could keep keep an off-screen bitmap for each of your windows and then restore them by copying each bit map into the corresponding window’s ports when they get their update events.
  2427. An alternate method is to make a single off-screen bitmap that is as large as the temporary window and a region that is the union of the content regions of your windows.  Before you display the temporary window, copy the screen into the off-screen bit map using the region as a mask.  After the temporary window is dismissed, restore the obscured area by copying from the off-screen bit map into a copy of the Window Manager port, and use the region as a mask.  If the region has the proper shape and location, it prevents _CopyBits from drawing outside of the content regions of your windows.  See Technical Note #194, WMgrPortability for details about drawing across windows.
  2428. In some cases it can be just as fast and convenient to simply define a picture (PICT) and then draw it into your window when necessary.  There are cases, however, such as text rotation, where it is advantageous to do the drawing off the screen, manipulate the bit image, and then copy the result to the visible window (thus avoiding the dangers inherent in writing directly to the screen).  In addition, this technique reduces flicker, because all of the drawing done off the screen appears on the screen at once.
  2429. It is also important to realize that, if you plan on using the pre-Color QuickDraw eight-color model, an off-screen bitmap loses any color information and you do not see your colors on a system that is capable of displaying them.  In this case you should either use a PICT to save the drawing information or check for the presence of Color QuickDraw and, when it is present, use a PixMap instead of a BitMap and the color toolbox calls (Inside Macintosh, Volume V) instead of the standard QuickDraw calls (Inside Macintosh, Volume I).
  2430. You may also want to refer to the OffScreen library (DTS Sample Code #15) which provides both high- and low-level off-screen bitmap support for the 128K and later ROMs.  The OffSample application (DTS Sample Code #16) demonstrates the use of this library.
  2431. Further Reference:
  2432. •    Inside Macintosh, Volumes I & IV, QuickDraw
  2433. •    Inside Macintosh, Volume V, Color QuickDraw
  2434. •    Technical Note M.IM.PrincipiaOffscreen —
  2435.         Principia Off-Screen Graphics Environments
  2436. •    Technical Note M.TB.WMgrPort —
  2437.          WMgrPortability
  2438. •    DTS Macintosh Sample Code #15, OffScreen & #16, OffSample
  2439. Old Style Colors
  2440. Imaging    M.IM.OldColors
  2441. Revised by:    Rich “I See Colors” Collyer    August 1990
  2442. Written by:    Rich “I See Colors” Collyer & Byron Han    October 1989
  2443. This Technical Note covers limitations of the original Macintosh color model (eight-color) which Inside Macintosh, Volume I-173, QuickDraw does not document.
  2444. Changes since October 1989:  Added definitions of the old-style constants.
  2445. QuickDraw has always been able to deal with color, just on a very limited basis.  Most applications have not made use of this feature, since Color QuickDraw-based Macintoshes come with a better color model.  There are, however, a few nice features which come with the old style color model.  With the old style colors, it is easy to print color on an ImageWriter with a color ribbon.  Another advantage is that developers do not have to write special-case code depending upon whether or not a machine has Color QuickDraw.
  2446. Now that you are ready to convert to the old style colors, there are a few things you should know about which do not work with old style colors.  This Note covers the limitations of using old style colors, as well as the best ways to work around these limitations.
  2447. Limitations
  2448. The most obvious limitation is that of only eight colors:  black, white, red, green, blue, cyan, yellow, and magenta.  This limitation is only a problem if you want to produce a color-intensive application; if this describes your application, then you need not read any further in this Note.
  2449. The next limitation is that off-screen buffers are not very useful.  You can draw into off-screen buffers, but there is no way to get the colors back from the buffer.  This leads into the next limitation, which is that _CopyBits cannot copy more than one color at a time.
  2450. When you call _CopyBits from an off-screen buffer to your window, you need to set the forecolor to the color you want to copy before calling _CopyBits (i.e., to copy a red object, call _ForeColor(redColor)).  Now when you copy the object, you can only copy one color.  If you copy different colored objects at one time, then you have a problem.  The result of a multicolored copy is that all objects copy in the same color, that of the foreground.
  2451. It is possible to work with an off-screen buffer and the old style colors, but it requires a lot of extra work.  Unless the objects are really complex, then it is probably easier to just draw the objects directly into your window.
  2452. One other limitation does exist.  Consider the following code sample.  One would assume that this sample would work at all times.
  2453.     SetPort (myPort);
  2454.     savedFG := myPort^.fgColor;
  2455.     ForeColor (redColor);            {or any other color}
  2456.     {...drawing takes place here...}
  2457.     ForeColor (savedFG);
  2458. Surprise.  It does not always work.  The saved value for the fgColor field of the GrafPort is not a classic QuickDraw color if the GrafPort is actually a CGrafPort.  If dealing with a CGrafPort, the fgColor field actually contains the foreground color’s entry in the color table, so the second call to _ForeColor really messes things up.
  2459. The proper way to set and reset the foreground color with classic QuickDraw’s _ForeColor call is as follows:
  2460.     SetPort (myPort);
  2461.     savedFG := myPort^.fgColor;
  2462.     ForeColor (redColor);            {or any other color}
  2463.     {...drawing takes place here...}
  2464.     myPort^.fgColor := savedFG;      {manually stuff the old fgColor back}
  2465.     If (32BQD = TRUE) Then           {32BQD is a flag which is made and set by}
  2466.         PortChanged (myPort);        {the application; to set it, the application}
  2467.                                      {needs to check _Gestalt for 32-Bit QuickDraw}
  2468. This Note also applies to the routine _BackColor.
  2469. What Works
  2470. The easiest way to work with these limited colors is to use pictures.  When you draw the images, you should draw into a picture.  Then when you want to draw the images into your window or to a printer, call _DrawPicture.  Pictures work well with the old style colors, and you don’t need to worry about making sure that the forecolor is current when you draw into your window.
  2471. Once you have the picture, you can use it to draw into the screen or to the printer port.  You can also set the WindowRecords windowPic to equal your PictureHandle so updates are handled by the Window Manager.
  2472. What Do Those Constants Mean Anyway
  2473. Each of the constants contains nine bits of information, and each bit has a special meaning.  Figure 1 illustrates the meaning of each of the bits, while Table 1 shows how each of the color constants fills in the appropriate bits.
  2474. Figure 1–Bit Definitions
  2475.     black    white    red    green    blue    cyan    magenta    yellow
  2476.     (33)    (30)    (209)    (329)    (389)    (269)    (149)    (89)
  2477. Cyan    0    0    0    1    1    1    0    0
  2478. Magenta    0    0    1    0    1    0    1    0
  2479. Yellow    0    0    1    1    0    0    0    1
  2480. Black    1    0    0    0    0    0    0    0
  2481. Red    0    1    1    0    0    0    1    1
  2482. Green    0    1    0    1    0    1    0    1
  2483. Blue    0    1    0    0    1    1    1    0
  2484. Inverse    0    1    0    0    0    0    0    0
  2485. Normal    1    0    1    1    1    1    1    1
  2486. Table 1–Color-Bit Correlation
  2487. Further Reference:
  2488. •    Inside Macintosh, Volume I-173, QuickDraw
  2489. •    Technical Note M.IM.Copybits —
  2490.         Of Time and Space and _CopyBits
  2491. Things You Wanted to Know About _PackBits*
  2492.     *But Were Afraid to Ask
  2493. Imaging    M.IM.PackBits
  2494. Revised by:    Guillermo Ortiz, Jon Zap, and Forrest Tanaka    January 1992
  2495. Written by:    Cameron Birse    November 1987
  2496. This Technical Note describes the format of data packed by the Toolbox utility _PackBits and documents a change to the srcBytes limit and possible worst case. Although you can simply unpack this data using _UnPackBits, Apple provides this information for the terminally curious and for those manipulating MacPaint® documents or PICT files by hand. 
  2497. Warning: This format information is subject to change.
  2498. Changes since November 1990: A warning has been added about the handling of a flag-counter byte value of -128.
  2499. Length Doesn’t Matter
  2500. Inside Macintosh, Volume I-470, describes the Pascal interface to the _PackBits trap as follows:
  2501.     PROCEDURE PackBits(VAR srcPtr,dstPtr:Ptr; srcBytes:INTEGER);
  2502. The accompanying text states that srcBytes, the length of your uncompressed data, should not be greater than 127, and that in the worst case, the compressed data can be srcBytes + 1. To pack more than 127 bytes, you had to break the data up into 127-byte groups and call _PackBits on each group. Beginning with system software version 6.0.2, this limit of 127 bytes is no longer valid. The new limit is 32,767 bytes, which is the maximum positive number that srcBytes can hold. The worst case can be determined according to the following formula:
  2503.     (srcBytes + (srcBytes+126) DIV 127)
  2504. which is comparable to what you would get if you broke up the data into 127-byte groups and picked up an additional byte for each group.
  2505. Mommy, How Do They Make Packed Bits?
  2506. The first byte is a flag-counter byte that specifies whether or not the the following data is packed, and the number of bytes involved. If this first byte is a negative number, then the following data is packed. In this case, the number is the two’s complement of a zero-based count of the number of times the data byte repeats when expanded. There is one data byte following this first byte in packed data. The byte after the data byte is the next flag-counter byte.
  2507. If the flag-counter byte is a positive number, then the following data is unpacked. In this case, the number is a zero-based count of the number of incompressible data bytes that follow. There are (flag-counter+1) data bytes following the flag-counter byte. The byte after the last data byte is the next flag-counter byte.
  2508. Note that there is no way to know, given a pointer to the start of packed data, when you have reached the end of the packed data. This is why you need to know either the length of the packed or unpacked data before you start unpacking. _UnPackBits requires the length of the unpacked data.
  2509. Warning:    _PackBits never generates the value -128 ($80) as a flag-counter byte, but a few PackBits-like routines that are built into some applications do. _UnpackBits handles this situation by skipping any flag-counter byte with this value and interpreting the next byte as the next flag-counter byte. If you’re writing your own UnpackBits-like routine, make sure it handles this situation in the same way.
  2510. Consider the following example:
  2511. Unpacked data:
  2512.     AA AA AA 80 00 2A AA AA AA AA 80 00 2A 22 AA AA AA AA AA AA AA AA AA AA
  2513. After being packed by _PackBits:
  2514.     FE AA                    ; (-(-2)+1) = 3 bytes of the pattern $AA
  2515.     02 80 00 2A              ; (2)+1 = 3 bytes of discrete data
  2516.     FD AA                    ; (-(-3)+1) = 4 bytes of the pattern $AA
  2517.     03 80 00 2A 22           ; (3)+1 = 4 bytes of discrete data
  2518.     F7 AA                    ; (-(-9)+1) = 10 bytes of the pattern $AA
  2519.        or
  2520.     FE AA 02 80 00 2A FD AA 03 80 00 2A 22 F7 AA
  2521.     *     *           *     *              *
  2522. The bytes with the asterisk (*) under them are the flag-counter bytes. _PackBits packs the data only when there are three or more consecutive bytes with the same data; otherwise it just copies the data byte for byte (and adds the count byte).
  2523. Note:    The data associated with some PICT opcodes, $0098 (PackBitsRect) and $0099 (PackBitsRgn), contain PixData which is basically made of _PackBits data. It should be noted, though, that the format for PixData includes a byteCount or length in addition to the data described in this Note.
  2524. For example, the following is the result of decoding a sample PICT2:
  2525. data 'PICT' (25534) {
  2526.     0936 0000 0000 0007 001E                /* pic size, picFrame */
  2527.     0011 02FF                               /* pict2              */
  2528.     0C00                                    /* header             */
  2529.          FFFF FFFF 0000 0000 0000 0000 001E 0000 0007 0000 0000 0000
  2530.     001E                                    /* def hilite         */
  2531.     0001                                    /* clipRgn            */
  2532.          000A 0000 0000 0007 001E
  2533.     0098                                    /* PackBitsRect       */
  2534.          801E                               /* rowbytes of 30     */
  2535.          0000 0000 0007 001E                /* Bounds             */
  2536.          0000                               /* packType           */
  2537.          0000                               /* version            */
  2538.          0000 0000                          /* packSize           */
  2539.          0048 0000                          /* hRes               */
  2540.          0048 0000                          /* vRes               */
  2541.          0000                               /* pixelType          */
  2542.          0008                               /* pixelSize          */
  2543.          0001                               /* cmpCount           */
  2544.          0008                               /* cmpSize            */
  2545.          0000 0000                          /* planeBytes         */
  2546.          0000 1F10                          /* pmTable            */
  2547.          0000 0000                          /* pmReserved         */
  2548.         /*color table*/
  2549.               0000 4CBC                     /* ctSeed             */
  2550.               8000                          /* ctFlags            */
  2551.               00FF                          /* ctSize             */
  2552.                    0000 FFFF FFFF FFFF
  2553.                    ...                 /* 254 ColorSpec's omitted */
  2554.                    0000 0000 0000 0000
  2555.          0000 0000 0007 001E                /* srcRect            */
  2556.          0000 0000 0007 001E                /* dstRect            */
  2557.          0000                               /* srcCopy            */
  2558.          /* Now we have the scan line data packed as follows:
  2559.             [bytecount for current scan line] [data as defined above]
  2560.             If rowBytes is > 250 then byteCount is a word else is a byte
  2561.             (in this case, byteCount is a byte)
  2562.             note that each unpacked row adds to 30 rowBytes
  2563.          */
  2564.          /* line 1, byte count is 2 (best case for a row)   */
  2565.          02
  2566.             E3 FF                /* -(-29) + 1 = 30 FF's    */
  2567.          /* line 2, byte count is 19 (0x13)                 */
  2568.          13
  2569.             01 FF 23             /* 1+1 data bytes          */
  2570.             FE 00                /* -(-2)+1 0's             */
  2571.             FC 23                /* -(-4)+1 0x23's          */
  2572.             FE 00                /* 3 0's                   */
  2573.             FC 23                /* 5 0x23's                */
  2574.             FE 00                /* 3 0's                   */
  2575.             FC 23                /* 5 0x23's                */
  2576.             FE 00                /* 3 0's                   */
  2577.             00 FF                /* 1 data byte             */
  2578.          /* line 3, byte count is 28                        */
  2579.          1C
  2580.             02 FF 00 23          /* 3 data bytes            */
  2581.             FE 00                /* 3 0's                   */
  2582.             FE 23                /* 3 0x23's                */
  2583.             01 00 23             /* 2 data bytes            */
  2584.             FE 00                /* 3 0's                   */
  2585.             FE 23                /* 3 0x23's                */
  2586.             01 00 23             /* 2 data bytes            */
  2587.             FE 00                /* 3 0's                   */
  2588.             FE 23                /* 3 0x23's                */
  2589.             04 00 23 00 00 FF    /* 5 data bytes            */
  2590.          /* line 4, byte count is 31 (worst case for a row) */
  2591.          1F
  2592.             03 FF 00 00 23       /* 4 data bytes            */
  2593.             FE 00                /* 3 0's                   */
  2594.             00 23                /* 1 data byte             */
  2595.             FE 00                /* 3 0's                   */
  2596.             00 23                /* 1 data byte             */
  2597.             FE 00                /* 3 0's                   */
  2598.             00 23                /* 1 data byte             */
  2599.             FE 00                /* 3 0's                   */
  2600.             00 23                /* 1 data byte             */
  2601.             FE 00                /* 3 0's                   */
  2602.             00 23                /* 1 data byte             */
  2603.             FE 00                /* 3 0's                   */
  2604.             02 23 00 FF          /* 3 data bytes            */
  2605.          /* line 5, byte count is 28                        */
  2606.          1C
  2607.             01 FF 00             /* 2 data bytes            */
  2608.             FE 23                /* 3 0x23's                */
  2609.             01 00 23             /* 2 data bytes            */
  2610.             FE 00                /* 3 0's                   */
  2611.             FE 23                /* 3 0x23's                */
  2612.             01 00 23             /* 2 data bytes            */
  2613.             FE 00                /* 3 0's                   */
  2614.             FE 23                /* 3 0x23's                */
  2615.             01 00 23             /* 2 data bytes            */
  2616.             FE 00                /* 3 0's                   */
  2617.             FE 23                /* 3 0x23's                */
  2618.             00 FF                /* 1 data byte             */
  2619.          /* line 6, byte count is 18                        */
  2620.          12
  2621.             00 FF                /* 1 data byte             */
  2622.             FC 23                /* 5 0x23's                */
  2623.             FE 00                /* 3 0's                   */
  2624.             FC 23                /* 5 0x23's                */
  2625.             FE 00                /* 3 0's                   */
  2626.             FC 23                /* 5 0x23's                */
  2627.             FE 00                /* 3 0's                   */
  2628.             FD 23                /* 4 0x23's                */
  2629.             00 FF                /* 1 data byte             */
  2630.          /* line 7, byte count is 2 (best case for a row)   */
  2631.          02
  2632.             E3 FF                /* 30 0xFF's               */
  2633.          00  /* pad so next command starts at word boundary */
  2634.     00FF                         /*end of pic               */
  2635. };
  2636. Further Reference:
  2637. •    Inside Macintosh, Volume I-465, The Toolbox Utilities
  2638. •    Inside Macintosh, Volume V-39, Color QuickDraw
  2639. •    Technical Note M.PT.MacPaintDoc —
  2640.          MacPaint Document Format
  2641. MacPaint is a registered trademark of Claris Corporation.
  2642. Palette Manager Changes in System 6.0.2
  2643. Imaging    M.IM.PaletteManagerChanges
  2644. Written by:    Guillermo Ortiz    October 1988
  2645. This Technical Note describes the changes and enhancements to the Palette Manager in System Software 6.0.2 and future versions.
  2646. Application Palette
  2647. Applications now have the ability to define a default palette for the system to use when it needs to define the color environment (i.e., when it creates a color window without an associated palette or displays a dialog box).
  2648. The application palette feature is especially cool in cases where a color application uses old-style dialogs and alerts because without an application palette, the system will use the default palette to define the color environment.  Since the system uses the default palette, the color environment may change (will change in 16-color mode) to cause some “cosmic” colors to appear in the active window.  Defining a default application palette with two colors, black and white, solves this problem.
  2649. If the system needs a palette to define a color environment, it looks in the resource fork of the application for the 'pltt' ID = 0 resource and uses the palette which it contains.  If the system cannot find this resource in the application’s resource fork, it will use its own default palette (resource 'pltt' ID = 0 in the System file) if present, or, if necessary, it will use the Palette Manager’s built-in palette.
  2650. Once an application has set its color environment (by calling _InitMenus, or _InitPalettes in weird instances when there are no menus) it can find the default palette by calling GetPalette ( WindowPtr (-1) ) or change the default palette by calling SetPalette ( WindowPtr (-1), newDefPltt, true ).  Note that the initialization of the Palette Manager with a call to _InitMenus is contrary to the way Inside Macintosh, Volume V, The Palette Manager documents it.
  2651. One Palette, Many Ports
  2652. You can now associate one palette with many CGrafPort and CWindow records, thus simplifying the use of a single palette with multiple ports and windows; System Software 6.0 and earlier require copies of the palette to use it with different windows.
  2653. Although this ability to associate one palette with multiple ports and windows will allow the use of calls like _PmForeColor and _PmBackColor, calling _ActivatePalette with an off-screen port does nothing, and as a result, calling it with an off-screen port will associate the palette with the port but will not cause any change in the color environment.
  2654. One important implication of this feature is that DisposeWindow (_DisposWindow) will not dispose of the associated palette automatically since it may be allocated to other ports or windows.  The only exception to this behavior is when an application has used _GetNewCWindow to create the window, there is a 'pltt' resource with the same ID as the window, and the application has not called _GetPalette for the window.
  2655. Color Updates
  2656. System version 6.0.2 also introduces a new call, _NSetPalette, which complements _SetPalette.  _NSetPalette has the same functionality as _SetPalette, but the CUpdates parameter has been modified from a Boolean to an Integer as follows:
  2657. PROCEDURE NSetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;
  2658.     nCUpdates: INTEGER);
  2659. INLINE $AA95;
  2660. _NSetPalette changes the palette associated with dstWindow to srcPalette.  It also records whether the window wants to receive updates as a result of a change to its color environment.  If you want dstWindow to be updated whenever its color environment changes, set nCUpdates to pmAllUpdates.  If you are only interested in updates when dstWindow is the active window, set nCUpdates to pmFgUpdates.  If you are only interested in updates when dstWindow is not the active window, set nCUpdates to pmBkUpdates.
  2661. { NSetPalette Update Constants }
  2662. pmNoUpdates =     $8000;    {no updates}
  2663. pmBkUpdates =     $A000;    {background updates only}
  2664. pmFgUpdates =     $C000;    {foreground updates only}
  2665. pmAllUpdates =     $E000;    {all updates}
  2666. _SetPalette retains its syntax and function:
  2667. PROCEDURE SetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;
  2668.     CUpdates: Boolean);
  2669. INLINE $AA95;
  2670. Note:    The trap words for _NSetPalette and _SetPalette are identical.
  2671. CopyPalette
  2672. PROCEDURE CopyPalette (srcPalette, dstPalette: PaletteHandle;
  2673.     srcEntry,dstEntry,dstLength: INTEGER);
  2674. INLINE $AAA1;
  2675. _CopyPalette is a utility procedure that copies dstLength entries from the source palette into the destination palette; the copy begins at srcEntry and dstEntry, respectively.  _CopyPalette will resize the destination palette when the number of entries after the copy is greater than the original.
  2676. _CopyPalette does not call _ActivatePalette, so the application is free to do a number of palette changes without causing a series of intermediate changes to the color environment; the application should call _ActivatePalette after completing all palette changes.
  2677. If either of the palette handles are NIL, _CopyPalette does nothing.
  2678. Palette Manager Q&As
  2679. Imaging    M.IM.PaletteMgr.Q&As
  2680. Revised by:    Developer Support Center    October 1992
  2681. Written by:    Developer Support Center    October 1990
  2682. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  2683. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  2684. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  2685. Macintosh Palette Manager and offscreen graphics
  2686. Written:    7/22/91
  2687. Last reviewed:    8/1/92
  2688. The Macintosh Palette Manager doesn’t work on offscreen environments the way you’d expect. Unlike color windows, SetPalette will not change the offscreen’s color table; rather it just allows you to use PMForeColor and PMBackColor to set the current drawing color in that environment. To change the offscreen’s color table you’ll need to convert the palette to a color table and then set the resulting color table to the off screen. Calling Palette2CTab will do the converting for you.
  2689. To get around having to use palettes to define the current drawing color in the off screen, you can always use Index2Color and then RGBForeColor to get the color to be set for drawing. A remake of GiMeDaPalette code sample, available on the latest Developer CD Series disc, does offscreen drawing in place of having to continually copy a PICT.
  2690. RestoreDeviceClut and color flash when application quits
  2691. Written:    8/23/91
  2692. Last reviewed:    8/1/92
  2693. When my application, which uses a color palette, quits, there is momentary but distracting flash of weird colors in the Finder windows and the desktop temporarily appears in a weird color. Is there any way to get around this?
  2694. ___
  2695. When you quit, RestoreDeviceClut is called to restore the color table and an update event is called to redraw the screen. It’s the delay between the change in the color table and the update event that causes the flash of incorrect colors to be displayed. This, unfortunately, is unavoidable.
  2696. Restoring Finder desktop colors after using Palette Manager
  2697. Written:    8/28/91
  2698. Last reviewed:    8/1/92
  2699. After using the Macintosh Palette Manager, how do I restore the Finder’s desktop colors?
  2700. ___
  2701. The Finder desktop’s colors are restored automatically on quitting applications that use the Palette Manager. Colors aren’t restored automatically when switching from your application to another, but if that application needs a certain set of colors and uses the Palette Manager to get them, then it’ll have them the moment it comes to the front. If you’re concerned about applications that don’t use the Palette Manager, you can use RestoreDeviceClut(gd:GDHandle), passing the handle to the GDevice of the screen you want to reset, or nil if you want to reset all of your devices. Passing nil to RestoreDeviceClut is your best bet, as it is very straightforward, and resets all of your monitors. You may not wish to do this, however, because RestoreDeviceClut is only available on machines with 32-bit color QuickDraw.
  2702. To reset a screen’s GDevice for machines without 32-bit color QuickDraw, you will need to keep track of the color table.When your application starts up, get the GDevice’s color table and save it—you’ll need it later. This value can be found at (**(**GDHandle).gdPMap).pmTable, where gdPMap is a PixMapHandle, and pmTable is a CTabHandle which tells you the absolute colors for this image. These data structures are found in Inside Macintosh Volume V, pages 52 and 119.
  2703. Build your application’s “world” using the Palette Manager, and avoid low-level methods of changing colors. When your application is about to quit and you want to restore the environment to its original state, get the color table you saved in the beginning. Convert this to a palette using CTab2Palette. Then set your window to this palette with SetPalette. This will cause the environment to update to the original color table that you initially got from the GDevice. If the application that is behind your application is Palette Manager friendly, then it will restore the environment to its palette. You may also want to do this procedure at the suspend event, as shown in the DTS sample MacApp program, FracApp. One of the problems that you won’t be able to solve this way involves multiple monitors. You won’t know which one to update. Only the monitor that has the window that you’ve called ActivatePalette on will update.
  2704. If your application changes the color environment with the Palette Manager, then RestoreDeviceClut is called automatically when your application quits. This means that you shouldn’t have to worry about restoring the palette if you don’t want to. There is a catch, however (there always is). When you use the SADE version of MultiFinder (6.1b9), it prevents this from automatically happening. Other versions of MultiFinder don’t have this side effect.
  2705. SetPalette cUpdates, NSetPalette, and window update events
  2706. Written:    9/26/91
  2707. Last reviewed:    8/1/92
  2708. When I pass false in the cUpdates parameter to SetPalette, I still get update events to that window when I modify its palette. What’s going on?
  2709. ___
  2710. SetPalette’s cUpdates parameter controls whether color-table changes cause that window to get update events only if that window is NOT frontmost. If that window is frontmost, then any changes to its palette causes it to get an update event regardless of what the cUpdates parameter is. When you call SetEntryColor and then ActivatePalette for your front-most window, it gets an update event because it’s the front-most window even though you passed false in the cUpdates parameter. Another important point is that windows that don’t have palettes also get update events even when another window’s palette is activated.
  2711. Fortunately, system software version 6.0.2 introduced the NSetPalette routine, which you can find documented in the Macintosh Technical Note “Palette Manager Changes in System 6.0.2,” and on page 20-20 in the revamped Palette Manager chapter of Inside Macintosh Volume VI. This variation of SetPalette gives you a lot more flexibility in controlling whether your window gets an update event than SetPalette does. If you pass pmAllUpdates in the nCUpdates parameter, then that window gets an update event when either it or another window’s palette is activated. If you pass pmFgUpdates, then it gets an update event when a palette is activated only if it’s the front-most window (in effect, it only gets an update event if its own palette is activated). If you pass pmBkUpdates, then it gets an update event when a palette is activated only if it’s not the front-most window (in effect, it only gets an update event if another window’s palette is activated). If you pass pmNoUpdates, then that window never gets an update event from any window’s palette being activated, including that window itself.
  2712. Picture Comments—The Real Deal
  2713. Imaging    M.IM.PictComments
  2714. Revised by:    Joseph Maurer    October 1992
  2715. Written by:    Ginger Jernigan    November 1986
  2716. Changes since March 1988: This Note (formerly titled “Optimizing for the LaserWriter—PicComments”) describes the picture comments defined and interpreted by the Apple printer drivers. Most of the picture comments are specific to PostScript, but we renamed the Note to emphasize that LaserWriter printers are not necessarily PostScript devices, and that QuickDraw printer drivers may implement their own picture comment handling. This Note has been completely rewritten and incorporates all additional insights gained during the last few years. We are also much more determined now to discourage the use of obsolete and problem-laden (although still supported) picture comments, and we carefully point out known problems or limitations of each comment.
  2717. Introduction
  2718. The QDProcs record (see Inside Macintosh Volume I, page 197) reflects the foundations of the architecture of QuickDraw. The commentProc field points to a procedure that processes picture comments, as included in a picture by means of the PicComment procedure (Inside Macintosh Volume I, page 189). This allows applications to include application-specific additional information in the pictures they create.
  2719. The QDProcs record also is the key to understanding how Macintosh printer drivers work. When the application calls PrOpenPage and draws into the printing grafPort, the printer driver collects the drawing commands by hooking into the QDProcs of the printing port. In particular, if an application calls the PicComment procedure while drawing into the printing grafPort, the printer driver gets a chance to capture and process the information contained in the kind and dataHandle parameters.
  2720. During the development of the original LaserWriter driver, it became obvious that applications should be able to take advantage of certain PostScript features that were not accessible through standard QuickDraw calls, such as rotated text and graphics, dashed lines, fractional line widths, and smoothed polygons. Also, certain applications needed a way to transmit their own native PostScript instructions to the printer. Picture comments seemed to be the ideal vehicle for providing these capabilities.
  2721. Unfortunately, there are conflicts with the device-independent nature of the Macintosh Printing Manager architecture. In this Note, we still want to document picture comments as completely and correctly as possible; and we want to tell you how to use the best of their features, while maintaining the important goal of device-independent printing and all- purpose PICTs. (This is why it has such a painful history!)
  2722. First, we give an overview of the picture comments as currently implemented by Apple’s printer drivers. This leads us immediately to the problem section “Cohabitation of QuickDraw and PostScript,” which also shows how to keep the QuickDraw and PostScript graphics states synchronized during printing. Finally, we discuss all the picture comments by subject, in the order suggested by Table 1.
  2723. Picture Comments Repertoire
  2724. The following picture comments are recognized by all PostScript LaserWriter drivers version 3.1 and later. 
  2725. Table 1-PostScript LaserWriter Picture Comments
  2726.     Type    Kind    Data Size    Data    Description
  2727.     TextBegin    150    6    TTxtPicRec    Begin text function
  2728.     TextEnd    151    0    NIL    End text function
  2729.     StringBegin    152    0    NIL    Begin string delimitation
  2730.     StringEnd    153    0    NIL    End string delimitation    TextCenter    154    8    TTxtCenter    Offset to center of rotation
  2731.     LineLayoutOff    155    0    NIL    Turn LaserWriter line layout off
  2732.     LineLayoutOn    156    0    NIL    Turn LaserWriter line layout on
  2733. #    ClientLineLayout    157    16    TClientLL    Customize line layout error 
  2734.                     distribution
  2735.     PolyBegin    160    0    NIL    Begin special polygon
  2736.     PolyEnd    161    0    NIL    End special polygon
  2737.     PolyIgnore    163    0    NIL    Ignore following polygon data
  2738.     PolySmooth    164    1    PolyVerb    Close, Fill, Frame
  2739.     PolyClose    165    0    NIL    Close the polygon
  2740.     DashedLine    180    -    TDashedLine    Draw following lines as dashed
  2741.     DashedStop    181    0    NIL    End dashed lines
  2742.     SetLineWidth    182    4    Point    Set fractional line widths
  2743.     PostScriptBegin     190    0    NIL    Set driver state to PostScript
  2744.     PostScriptEnd     191    0     NIL    Restore QuickDraw state
  2745.     PostScriptHandle    192    -    PSData     PostScript data in handle
  2746. †    PostScriptFile    193    -    FileName    FileName in data handle
  2747. †    TextIsPostScript    194    0    NIL    QuickDraw text is sent as PostScript
  2748. †    ResourcePS    195    8    Type/ID/Index    PostScript data in a resource file
  2749.     PSBeginNoSave    196    0    NIL    Set driver state to PostScript
  2750. #    SetGrayLevel    197    4    Fixed    Call PostScript’s setgray operator
  2751.     RotateBegin    200    4    TRotation    Begin rotated port
  2752.     RotateEnd    201    0    NIL    End rotation
  2753.     RotateCenter    202    8    Center    Offset to center of rotation
  2754. #    FormsPrinting    210    0    NIL    Don’t clear print buffer after each                     page
  2755. #    EndFormsPrinting    211    0    NIL    End forms printing after PrClosePage
  2756. _______________________________
  2757. †    These comments are obsolete.
  2758. #    These comments are not recommended.
  2759. Most of the comments in Table 1 were designed specifically for the original LaserWriter driver. In fact, the term LaserWriter has been (and often still is) used in the sense of “PostScript printer,” and the LaserWriter driver is known to be basically a QuickDraw-to-PostScript translator. Meanwhile, however, QuickDraw-based LaserWriter models came out, so we should start being more careful in our terminology. This is why we insist on talking about PostScript drivers or PostScript printers when a picture comment applies to PostScript.
  2760. QuickDraw printer drivers may implement their own picture comments, or some of the above comments, in order to provide additional capabilities. Certain third-party printer drivers implement text rotation, for example, by supporting the TextBegin/TextCenter/ TextEnd picture comments.
  2761. Apple’s QuickDraw printer driver for the LaserWriter SC supports the following three picture comments:
  2762.     LineLayoutOff    155    0    NIL    Turn LaserWriter line layout off
  2763.     LineLayoutOn    156    0    NIL    Turn LaserWriter line layout on
  2764.     SetLineWidth    182    4    Point    Set fractional line widths.
  2765. The ImageWriter LQ driver and the first versions of the StyleWriter driver (prior to 7.2) implement the LineLayoutOff and LineLayoutOn picture comments. Even the ImageWriter driver reacts to picture comments:
  2766.     BitMapThinningOff    1000    0    NIL    Turn off hi-res bitmap thinning
  2767.     BitMapThinningOn    1001    0    NIL    Turn on hi-res bitmap thinning
  2768. The ImageWriter driver does the same toggling of the “bitmap thinning” of fat bitmaps in Best mode, when it encounters a TextBegin or TextEnd comment (undocumented feature—never mind!). The ImageWriter LQ driver handles these comments similarly.
  2769. The current StyleWriter driver (version 7.2.2) and the personal LaserWriter LS driver do not support any picture comments at all. 
  2770. The point of all this is:
  2771. It is impossible to determine which picture comments
  2772. are supported by which printer driver.
  2773. In other words, your application should never assume a particular picture comment is available, but your application also should not defeat the device-independent design of the Macintosh printing architecture by writing printer driver–specific code! 
  2774. Of course, you know (Inside Macintosh Volume II, page 152) that the high byte of the prStl .wDev field of the print record identifies a printer driver species, and that a value of $03 tells you the printer driver belongs to the PostScript LaserWriter driver ancestry. As a matter of fact, many applications use this information to achieve special printing features not available through the Printing Manager interface.
  2775. And, of course, you also know that we don’t like this idea. One reason is future system software may allow spool files to be redirected to a printer other than the one chosen when you sent your printing instructions (including picture comments). Another reason is that picture comments usually are included in PICTs; documents containing such pictures should print with optimal results on any printer configuration. And, finally, you never know what the future holds for you, in terms of new printing devices or new printer drivers—or a new printing architecture!
  2776. Instead, if a picture (i.e., a sequence of imaging instructions) contains picture comments to enhance the output on devices that support them, it should also contain a standard QuickDraw representation as a fallback solution, in case the rendering device does not recognize the picture comments. The design and implementation of these picture comments should incorporate conventions to make this cohabitation of two representations in one picture possible.
  2777. Cohabitation of QuickDraw and PostScript
  2778. Device-Independent Pictures
  2779. We can think of the Printing Manager’s PrOpenPage and PrClosePage calls as being analogous to the OpenPicture and ClosePicture calls (which, by the way, reminds us to never call OpenPicture between PrOpenPage and PrClosePage; see Inside Macintosh Volume II, page 160). In both cases, a stream of imaging instructions is recorded for deferred rendering. We want to create pictures that include both QuickDraw and optimized PostScript representations so that we obtain the best results in all circumstances. We must take special care for third-party QuickDraw printer drivers that support picture comments originally intended for PostScript devices only.
  2780. Let’s start with the easy ones.
  2781. The two picture comments PostScriptBegin and PostScriptEnd clearly suggest that any imaging instructions in between are intended exclusively for PostScript printing devices. In the case of the PostScript LaserWriter driver, the effect of PostScriptBegin is to disable all bottlenecks except commentProc, txMeasProc, getPicProc, and putPicProc. This means that QuickDraw’s text, line, shape (Rects, RoundRects, Ovals, Arcs, Polygons) and bitmap drawing calls don’t have any effect in the printing grafPort when enclosed by PostScriptBegin and PostScriptEnd. Instead, the PostScript LaserWriter driver expects to receive the imaging instructions as data enclosed in the PostScriptHandle comment. This way, both the PostScript and QuickDraw representation can coexist in the same picture without conflict. As a consequence, non-PostScript printer drivers, unable to interpret general PostScript text, must not imitate this behavior of ignoring QuickDraw instructions, even when they implement other picture comments such as TextBegin and TextEnd for text rotation. Otherwise, they would miss the QuickDraw representation of some PostScript imaging.
  2782. The text rotation picture comments (TextBegin, TextCenter, TextEnd) silently include the assumption that a printer driver that supports these comments
  2783. a. ignores the QuickDraw clipping region between TextBegin and TextEnd
  2784. b. ignores the QuickDraw CopyBits instruction within TextBegin/TextEnd
  2785. This way, a bitmap representation of the rotated text can be included in the picture. It will be used only if the TextBegin/TextEnd comments are not supported. Conversely, the QuickDraw commands required to draw the text to be rotated by the printer driver are “hidden” from QuickDraw by setting the clipping region to empty, which is ignored by the driver supporting the comments.
  2786. The polygon picture comments provide another solution to the problem, in form of the special comment PolyIgnore. It allows one to include a QuickDraw representation of the smoothed polygon, ignored by a driver that supports polygon smoothing (such as via PostScript’s curve operator). And for filled polygons, QuickDraw’s region concept works around a conflict of who owns which polygon (see sample code later in this Note).
  2787. Some picture comments (such as the line layout comments) do not require a fallback solution in case they are not supported by a printer driver; or the feature, if absent, is not a big loss (such as SetLineWidth, provided you use it only for widths smaller than one 72-dot-per-inch (dpi) QuickDraw pixel). 
  2788. But for the picture comments DashedLine/DashedStop and RotateBegin/ RotateCenter/RotateEnd, there is no general solution to the “cohabitation” problem; and we are distressed about it. It is obvious that they have been defined with the PostScript LaserWriter driver in mind, without anticipating a future furnished by some 150 third-party printer drivers. The only way to include both representations in these cases is indeed to assume that only PostScript drivers will support the picture comment, such that the PostScriptBegin and PostScriptEnd comments can be used to “comment out” the QuickDraw representation.
  2789. Even under the above assumption, we still need a trick to prevent the QuickDraw calls within the scope of the picture comments from showing up when the comments are not recognized. Fortunately, early Macintosh developers discovered a QuickDraw feature that, unintentionally, solves the problem. Passing the “magic” mode 23 to PenMode inhibits QuickDraw’s normal drawing, but still lets the LaserWriter driver see the drawing instructions come through the bottlenecks, so that it can translate them into PostScript. Note that this pen mode always has been undocumented, and that using it was considered a compatibility risk and frowned upon for some time. Given the current state of affairs, however, there is no reason anymore to be paranoid about it.
  2790. Keeping QuickDraw and PostScript Synchronized
  2791. There are two situations, in the context of picture comments, where the design of the PostScript LaserWriter driver requires special precautions from the application programmer. 
  2792. First, certain QuickDraw instructions like Move, MoveTo, PenPat, and PenSize change the state of the grafPort, without going through the QDProcs bottleneck procedures. A Macin-tosh printer driver takes these changes into account only at the time it executes an actual drawing instruction. Remember, the printer driver hooks into the QDProcs to get execution time and only “sees” instructions coming through the QDProcs. Nothing is wrong with it—unless PostScript code is woven into the graphics instructions by means of picture comments. (Note that PostScript code may be generated transparently when the LaserWriter driver encounters certain picture comments.) If the PostScript code assumes that the current state of the grafPort corresponds to what you expect it to be, then you have to flush the state of the grafPort explicitly before inserting the PostScript code. This is easier than it sounds; just do something inoffensive that goes through the QDProcs.lineProc bottleneck, like in the following utility procedure:
  2793. PROCEDURE FlushGrafPortState;
  2794. { This routine causes the state of the Printing Manager's grafPort to be }
  2795. { flushed out to the LaserWriter, by making a dummy call through the     }
  2796. { QDProcs.lineProc bottleneck. Pen size and pen location are preserved.  }
  2797.    VAR
  2798.       penInfo: PenState;
  2799.    BEGIN
  2800.       GetPenState(penInfo);                              { Save pen size. }
  2801.       PenSize(0,0);                                  { Make it invisible. }
  2802.       Line(0,0);                           { Go through QDProcs.lineProc. }
  2803.       PenSize(penInfo.pnSize.h, penInfo.pnSize.v);    { Restore pen size. }
  2804.    END;
  2805. Another unwanted effect is related to the PostScript LaserWriter driver’s multiple internal buffering of generated PostScript code. The PostScript code generated for text drawing instructions (which usually involves font queries and, sometimes, font downloading) is buffered independently from the PostScript code inserted by means of picture comments. In certain cases, this results in apparently nonsequential execution of drawing instructions, and may affect clipping regions or may have side effects on the PostScript code you included in picture comments. In order to synchronize the sequence of QuickDraw instructions with the generation of PostScript code, you need to call the following procedure:
  2806. PROCEDURE FlushPostScriptState;
  2807. { This routine flushes the buffer maintained by the LaserWriter driver. }
  2808. { All PostScript, generated either by the app or by the LaserWriter     }
  2809. { driver, will be sent to the device.                                   }
  2810.    BEGIN
  2811.       PicComment(PostScriptBegin, 0, NIL);
  2812.       PicComment(PostScriptEnd, 0, NIL);
  2813.    END;
  2814. In the following discussion of picture comments, we’ll refer to these two utility routines as appropriate.
  2815. Text Rotation
  2816. Comments:    TextBegin, TextCenter, TextEnd
  2817. These comments give access to PostScript’s capabilities of rotating, flipping, and justifying text. They are intended for applications likely to be used with PostScript printers (such as desktop publishing and advanced drawing applications), but which don’t want to use PostScript explicitly. Note that some non-PostScript printer drivers support these comments as well. For situations where the comments are not supported (such as the QuickDraw screen, or most QuickDraw printer drivers), you must provide a bitmap represen-tation of the rotated text as an alternative. 
  2818. Let’s look at sample code right away.
  2819. USES  PicComments;  { See Appendix; defines constants for just and flip and   }
  2820.                     { the structures referred to by TTxtPicHdl and TCenterHdl.}
  2821.    
  2822. PROCEDURE QDStringRotation(s: Str255; ctr: Point; 
  2823.                            just, flip: Integer; rot: Fixed); EXTERNAL;
  2824. { This routine should generate a bitmap of the rotated and flipped text       }
  2825. { and use CopyBits to draw it to the grafPort. Left as an exercise ...        }
  2826. PROCEDURE DrawXString(s: Str255; ctr: Point; just, flip: Integer; rot: Fixed);
  2827. { Draws the string s rotated by rot degrees around the current point, offset  }
  2828. { by ctr, justifying and flipping according to the just and flip parameters.  }
  2829. { If the printer driver supports the TextBegin, TextCenter, and TextEnd       }
  2830. { picture comments, it rotates the text at device resolution; otherwise, the  }
  2831. { external procedure QDStringRotation is called to image the rotated string.  }
  2832. { The pen position is preserved. }
  2833.    VAR
  2834.       hT: TTxtPicHdl;     { Defined in PicComments.p - see Appendix. }
  2835.       hC: TCenterHdl;     { –"– }
  2836.       zeroRect: Rect;
  2837.       pt: Point;
  2838.       oldClip: RgnHandle;
  2839.    BEGIN
  2840.       GetPen(pt);  { to preserve the pen position }
  2841.       hT := TTxtPicHdl(NewHandle(SizeOf(TTxtPicRec)));
  2842.       hC := TCenterHdl(NewHandle(SizeOf(TCenterRec)));
  2843.       { No error handling: if these fail, we are in deep trouble anyway ...}
  2844.       WITH hT^^ DO BEGIN
  2845.          tJus      := just;
  2846.          tFlip     := flip; 
  2847.          tAngle    := - FixRound(rot); { I like counterclockwise better. }
  2848.          tLine     := 0; { reserved }
  2849.          tCmnt     := 0; { used internally by the printer driver }
  2850.          tAngleFixed := - rot;
  2851.       END;
  2852.       hC^^.y := Long2Fix(ctr.v);
  2853.       hC^^.x := Long2Fix(ctr.h);
  2854.       PicComment(TextBegin,SizeOf(TTxtPicRec),Handle(hT));
  2855.       PicComment(TextCenter,SizeOf(TCenterRec),Handle(hC));
  2856.       { PostScript graphics state now has rotated/flipped coordinates. }
  2857.       oldClip := NewRgn;
  2858.       GetClip(oldClip);
  2859.       SetRect(zeroRect,0,0,0,0);
  2860.       ClipRect(zeroRect);  { Hides the following DrawString from QuickDraw }
  2861.       DrawString(s); { in the rotated PostScript environment. }
  2862.       ClipRect(oldClip^^.rgnBBox);
  2863.       { Now the "fallback" bitmap representation; see the comments above  }
  2864.       { at the declaration of the QDStringRotation procedure. }
  2865.       QDStringRotation(s, ctr, just, flip, rot);
  2866.       PicComment(TextEnd,0,NIL); { Set environment back to the original state }
  2867.       DisposHandle(Handle(hT));
  2868.       DisposHandle(Handle(hC));
  2869.       MoveTo(pt.h,pt.v);  { to preserve the pen position }
  2870.    END;
  2871. The preceding discussion about including both QuickDraw and PostScript representations and the comments included in the source code say it all: The conventions tied to the usage of the TextBegin and TextEnd picture comments allow you to take advantage of a printer driver’s implementation of high-resolution text rotation, while including a bitmapped representation for where the comments are not supported.
  2872. Some Additional Hints
  2873. •    Because of QuickDraw’s orientation of the vertical coordinate axis, the rotation angle is measured clockwise. Nothing prevents us from using the negative angle if we are used to the counterclockwise orientation.
  2874. •    The angle is measured in degrees (0..360), and passed as a Fixed type number (that is, if taken as a LongInt value, you have to divide it by 65536 to obtain the angle in degrees). For integer angles, it is possible to use a reduced TTxtPicRec structure that does not contain the tRotFrac field. The PostScript LaserWriter driver uses GetHandleSize(hT) to determine whether it must use the fractional angle in the tRotFrac field. To be safe, always set the tRot field to FixRound(tRotFrac) if you go with the extended TTxtPicRec (as we do here).
  2875. •    It is convenient that clipping regions are ignored between the TextBegin and TextEnd picture comments, because it allows us to clip out the DrawString on printers that don’t support these comments. Unfortunately, this also means that text rotated this way can’t be clipped. If clipping of rotated text is required, you’ll have to do it entirely within PostScript.
  2876. •    Due to the LaserWriter driver’s internal buffering of generated PostScript code, the effect of ignoring clip regions may be propagated to preceding sections of your drawing instructions. We recommend calling the FlushPostScriptState procedure described earlier immediately before the TextBegin comment.
  2877. •    The tJus field in the TTxtPicRec, if different from tJusNone, tells the printer driver to maintain either the left, right, or center point of the string without recalculating the interword and intercharacter spacing. The tJusFull value specifies that the original length of the string (on the QuickDraw screen) must be maintained. This is important when the printer font has widths different from those of the screen font, and when you rotate justified blocks of text.
  2878. •    The tFlip field in the TTxtPicRec specifies horizontal or vertical flipping about the center point specified by the TextCenter comment.
  2879. •    The TextCenter comment specifies the center of rotation for any text enclosed within the TextBegin and TextEnd calls, as an offset to the location of the current point. The rotation is achieved by changing PostScript’s coordinate system. A sequence of DrawString – MoveTo instructions is rotated as a whole until TextEnd is encountered.
  2880. •    Some versions of double-byte Kanji systems print Kanji characters by calling CopyBits instead of calling standard text drawing routines. This means the comments in the Text Rotation family cannot be used with these fonts. Instead, use the Graphics Rotation comment family described later in this Note.
  2881. Line Layout Control
  2882. Comments:    LineLayoutOn, LineLayoutOff, ClientLineLayout
  2883. When drawing to a printing grafPort, the selected printer driver does a lot of work “behind the scenes” to try to maintain the infamous “What-You-See-Is-What-You-Get” (WYSIWYG) metaphor from the screen to the paper, and generally to make the printed output look as good as possible. Depending on the target device, the printer driver, and the configuration of fonts in the system, the font you draw text with may be scaled, smoothed, remapped, or even replaced by a font built into the printer. In nearly all cases where the device resolution of the printer is different from QuickDraw’s “hard-coded” 72-dpi screen resolution, the width of text rendered on the printer is different from the text width on the screen. This is due to nonproportionally scaling bitmapped fonts, different character widths after font substitution, and rounding errors of fractional character widths on the screen. The difference in the width of a line of text is called the line layout error.
  2884. The printer driver is responsible for adjusting the word and character spacing in the printed output so that the two widths are identical. If it doesn’t, apparently fully justified text on the screen may appear ragged on the paper, and certain lines of text may extend beyond the right border and be badly clipped. Many existing applications make this task really difficult for the printer drivers (don’t blame them, though!). They position the words (or even characters) separately on a line, and the printer driver has to figure out how to collect the complete line before applying its line layout algorithm to distribute the difference of the text widths into word and character spacing. Given the uneven distribution of the character width differences, and the requirement of achieving good typographical quality in the printed output, it is unavoidable that the position and width of a word within a justified line differs slightly from what appears on the screen; only the length of the whole line is maintained.
  2885. In computing the required line layout adjustments, the LaserWriter driver proceeds as follows:
  2886. 1.    It collects text coming through the printing grafPort’s textProc bottleneck, and heuristically puts it together into what it “believes” is a logically contiguous line of text. This includes text moved vertically away from the baseline, to take care of indices or exponents in the text. The process of accumulating text is stopped when the LaserWriter driver detects that the horizontal component of the pen position has changed since the previous text drawing instruction, or when picture comments like TextBegin, TextEnd, StringBegin, StringEnd are encountered.
  2887. 2.    It determines the width of the accumulated logical line of text, both on the screen and on the printer, and distributes the line layout error among the interword and intercharacter spacing of the printed output.
  2888. The LineLayoutOff picture comment disables only the second step (distribution of the line layout error); the heuristic algorithm of accumulating text into a logically contiguous piece is not affected. Otherwise, if the character widths of the printer font are different from those of the screen font, and if the text contains exponents or indices, the latter would often be misplaced.
  2889. The following code fragment shows a probably unexpected consequence of this behavior. We draw a line in two pieces three times. A vertical line shows the starting pen position of the second DrawString call. The second line is enclosed by LineLayoutOff and LineLayoutOn picture comments.
  2890. PROCEDURE ObserveLineLayout;
  2891.    CONST
  2892.       testString1 = 'Whatever you like, preferably ';
  2893.       testString2 = 'with spaces, long and short words';
  2894.       fontName = 'New York';
  2895.       fontSize = 14;
  2896.       x0 = 20; { starting point }
  2897.       y0 = 40;
  2898.       h  = 30; { line height }
  2899.    VAR
  2900.       familyID: Integer;
  2901.       w, y    : Integer;
  2902.    BEGIN
  2903.       GetFNum(fontName, familyID);
  2904.       TextFont(familyID);
  2905.       TextSize(fontSize);
  2906.  
  2907.       w := StringWidth(testString1);
  2908.       y := y0;
  2909.       MoveTo(x0 + w, y - h);
  2910.       Line(0, 4 * h);    { This is to estimate the difference. }
  2911.       { Draw the first line, in two pieces. }
  2912.       { This is the default line layout behavior of the LaserWriter driver. }
  2913.       MoveTo(x0, y);          
  2914.       DrawString(testString1);
  2915.       MoveTo(x0 + w, y);
  2916.       DrawString(testString2);
  2917.       { Draw the second line, in the same way as above. }
  2918.       { Because of the LineLayoutOff picture comment, the unmodified widths }
  2919.       { of the printer font are used. }
  2920.       y := y + h;
  2921.       PicComment(LineLayoutOff, 0, NIL);
  2922.                                    { ••• (1)  •••}
  2923.       MoveTo(x0, y);
  2924.       DrawString(testString1);
  2925.       MoveTo(x0 + w, y);
  2926.                                    { ••• (2)  •••}
  2927.       DrawString(testString2);
  2928.       y := y + h;
  2929.       PicComment(LineLayoutOn, 0, NIL);
  2930.       { Back to the original behavior. }
  2931.       MoveTo(x0, y);
  2932.       DrawString(testString1);
  2933.       MoveTo(x0 + w, y);
  2934.       DrawString(testString2);
  2935.    END;
  2936. And this is (approximately) the output of the ObserveLineLayout (with LaserWriter driver version 7.1.1, and the default setting “Font Substitution enabled”):
  2937. Figure 1—Effect of the LineLayoutOff comment
  2938. For most noticeable effects, we choose the bitmapped New York font, such that the LaserWriter driver substitutes PostScript Times (note that there are no line layout problems with TrueType fonts, unless the TrueType font has the same name and different cha-rac-ter widths as a printer-resident PostScript font). The screen font New York is larger than the PostScript font Times, and in the first and third lines, the printer driver (after accumulating testString1 and testString2 into one logical line) distributes the line layout error (mainly) among the spaces between words. You may even notice that the starting point of testString2 (“with ...”) has been slightly moved to the left in the process. The width of the whole line, however, is the same as on the screen.
  2939. The second line, where the LineLayoutOff comment is active, demonstrates a dramatic counterexample to the popular belief that this picture comment is here to assure precise positioning of text. It seems the opposite is true, and the LaserWriter driver has deliberately ignored the MoveTo(x0+w,y) instruction! What we would have expected is this:
  2940. Figure 2—Desired result of the LineLayoutOff comment
  2941. The attentive reader already knows the explanation. As mentioned earlier, we must break the LaserWriter driver’s heuristic line accumulation algorithm before drawing testString2. Short of adequate documentation, developers have found out that a FlushGrafPortState call right after the MoveTo(x0+w,y) instruction has the desired effect (see {••• (2) •••} in the code snippet given earlier). Unfortunately, it creates quite a lot of overhead in the pictures, and penalizes all printer drivers that don’t need it. A better solution is to use the StringBegin and StringEnd picture comments at the markers {••• (1) •••} and {••• (2) •••} in the code shown earlier. This indicates that testString1 is to be considered a logically independent text entity, and must not be put together with any other pieces of text coming through the textProc bottleneck. The overhead of these comments is much smaller, and they don’t affect other printer drivers at all.
  2942. The ClientLineLayout picture comment, supported by the (PostScript) LaserWriter driver, has never been documented. Its effect is rather subtle and very specific to the PostScript LaserWriter driver. Basically, it allows the application to redefine the character that absorbs the major part of the line layout error (usually the space character), and the percentages of the “major” and “minor” parts of the line layout error (usually 80 percent versus 20 percent). The “minor” part is distributed across intercharacter spacing. 
  2943. Only very ambitious page layout applications might be interested in this functio-na-lity; but then, they should rather aim at a more general scheme of line layout control that does not rely upon this very driver-specific picture comment.
  2944. The PicComment.p interface (see the Appendix) describes the TClientLLRecord structure passed through the handle parameter to the picture comment. If you want, feel free to experiment with it; we recommend, however, that you do not use this picture comment in your application. 
  2945. Caveats
  2946. • Some older printer drivers supporting the LineLayoutOff picture comment are unable to correctly obey a subsequent LineLayoutOn picture comment.
  2947. • Don’t forget that if you use LineLayoutOff, the burden of “WYSIWYG” is now on your shoulders, and not the printer driver’s.
  2948. • A previous version of this Note said that setting the Font Manager’s FractEnable global to TRUE implied the effect of the LineLayoutOff picture comment. As it turned out, the statement was based on observations with a specific (older) version of the LaserWriter driver, and is not true in general. The setting of FractEnable does have some more or less subtle effects on the line layout algorithm, however; and this is quite plausible. Similarly, the results of combining the picture comments LineLayoutOff and LineLayoutOn with calls to SpaceExtra (Inside Macintosh Volume I, page 172) or CharExtra (Inside Macintosh Volume V, page 77) are sometimes unpredictable, depending on the particular printer driver.
  2949. And Finally the Good News
  2950. Given that the effect of the LineLayoutOff and LineLayoutOn comments does not require any changes in your printing code, you don’t have to worry whether or not a particular driver supports them. They are useful mainly when you’re sure you want no external assistance in computing word and character spacing for full justification, or when you need precise control over the horizontal placement of words and characters (such as in forms or tabulated text) and understand how to achieve this.
  2951. String Delimitation 
  2952. Comments:    StringBegin, StringEnd
  2953. These comments allow applications to specify the logical beginning and end of a string, possibly drawn with multiple calls to a QuickDraw text drawing routine (such as DrawChar). If this was their only raison d’être, they would have no relationship with the PostScript LaserWriter driver. But, as already let out in the preceding section on line layout, they are important to notify the printer driver that it should consider the text coming through the textProc bottleneck between StringBegin and StringEnd as an independent entity. Otherwise, the driver might continue to perform its heuristic accumulation of text drawing instructions for the same line, and defeat your text positioning intentions. Indeed, both StringBegin and StringEnd trigger the generation of PostScript instructions for drawing the text that has been accumulated in a line layout buffer, and reinitialize the internal variables for line layout computations. In other words, you need these picture comments to turn the LaserWriter driver’s line layout behavior completely off.
  2954. Polygon Comment Family
  2955. Comments:    PolyBegin, PolyEnd, PolyClose, PolySmooth, PolyIgnore
  2956. PostScript has the built-in capability of drawing cubic Bézier curve sections (see the PostScript Language Reference Manual, Second Edition, page 393). This is convenient for “smoothing” of polygons. The polygon-related picture comments have been provided to give applications easy access to this PostScript feature, with provision for including a QuickDraw approximation of the curve.
  2957. Schematically, the polygon comments are used as follows:
  2958.     PolyBeginComment;    { Put the PostScript driver into “polygon mode.” }
  2959.     ClipRect(zeroRect);        { Hide the following from QuickDraw. }
  2960.     PolyCloseComment;    { Optionally, if “closed” smoothing desired. }
  2961.     PolySmoothComment;    { Tell the driver to draw a Bézier curve. }
  2962.     DrawPolygon;        { Invisible for QuickDraw; PostScript output = curve. }
  2963.     PolyIgnoreComment;    { The driver will ignore the following line drawing. }
  2964.     SetClip(origClipRgn);    { Make it visible for QuickDraw. }
  2965.     DrawQDPolygon;        { Usually, a QuickDraw approximation of the curve. }
  2966.     PolyEndComment;        { PostScript driver resumes standard mode. }
  2967. A piece of sample code is sometimes worth more than one or two pictures; below, you’ll find both. For clarity and completeness of the exposition, we provide the coordinate definition of the polygons through arrays of Points, initialized in a preliminary DefineVertices procedure. You can enclose the PolygonDemo procedure between OpenPicture and ClosePicture calls to create a picture containing both QuickDraw and PostScript representations (see Figures 3 and 4), or you can use it as is when a printing page is open.
  2968. USES PicComments;
  2969. { See Appendix of this Note for the definition of the TPolyRec structure. }
  2970.    CONST
  2971.       kN = 4; { number of vertices for PostScript }
  2972.       kM = 6; { number of vertices for QuickDraw approximation }
  2973.    TYPE
  2974.       PointArray = array[0..0] of Point;  { range checking OFF }
  2975.       PointArrayPtr = ^PointArray;
  2976. PROCEDURE DefineVertices(VAR p,q: PointArrayPtr);
  2977.    CONST
  2978.       cx = 280;
  2979.       cy = 280;
  2980.       r0 = 200;
  2981.    BEGIN
  2982.    { The array p^ contains the control points for the Bézier curve: }
  2983.       SetPt(p^[0],cx + r0,cy);
  2984.       SetPt(p^[1],cx,cy + r0);
  2985.       SetPt(p^[2],cx - r0,cy);
  2986.       SetPt(p^[3],cx,cy - r0);
  2987.       p^[4] := p^[0];
  2988.    { q^ contains the points for a crude polygon approximation of the curve: }
  2989.       q^[0] := p^[0];
  2990.       SetPt(q^[1],cx,cy + round(0.7 * (p^[1].v - cy)));
  2991.       SetPt(q^[2],(p^[1].h + p^[2].h) DIV 2,(p^[1].v + p^[2].v) DIV 2);
  2992.       SetPt(q^[3],cx + round(0.8 * (p^[2].h - cx)),cy);
  2993.       SetPt(q^[4],q^[2].h,cy + cy - q^[2].v);
  2994.       SetPt(q^[5],q^[1].h,cy + cy - q^[1].v);
  2995.       q^[6] := q^[0];
  2996.    END;
  2997. PROCEDURE PolygonDemo;
  2998.    VAR
  2999.       p,q: PointArrayPtr;
  3000.       aPolyVerbH: TPolyVerbHdl;
  3001.       i: Integer;
  3002.       clipRgn, polyRgn: RgnHandle;
  3003.       zeroRect: Rect;
  3004.    BEGIN
  3005.       p := PointArrayPtr(NewPtr(SizeOf(Point) * (kN + 1)));
  3006.       q := PointArrayPtr(NewPtr(SizeOf(Point) * (kM + 1)));
  3007.       IF (p = NIL) OR (q = NIL) THEN DebugStr('NewPtr failed');
  3008.       DefineVertices(p,q);
  3009.       PenNormal;              { First show the standard QuickDraw polygon. }
  3010.       MoveTo(p^[0].h,p^[0].v);
  3011.       FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);
  3012.    
  3013.       PenSize(2,2);                { Now show the same polygon "smoothed." }
  3014.       PenPat(gray);
  3015.       { First, the PostScript representation, clipped off from QuickDraw: }
  3016.       aPolyVerbH:= TPolyVerbHdl(NewHandle(SizeOf(TPolyVerbRec)));
  3017.       IF aPolyVerbH<> NIL THEN
  3018.          WITH aPolyRecH^^ DO BEGIN        { ••• See comment 1, below. ••• }
  3019.             fPolyFrame := TRUE;
  3020.             fPolyFill  := FALSE;
  3021.             fPolyClose := FALSE;     { Compare with the result for TRUE ! }
  3022.             f3 := FALSE;
  3023.             f4 := FALSE;
  3024.             f5 := FALSE;
  3025.             f6 := FALSE;
  3026.             f7 := FALSE;
  3027.          END;
  3028.       MoveTo(p^[0].h,p^[0].v);            { ••• See comment 2, below. ••• }
  3029.       PicComment(PolyBegin,0,NIL);
  3030.    {  PicComment(PolyClose,0,NIL);  <<< Only if fPolyClose = TRUE, above! }
  3031.       PicComment(PolySmooth,SizeOf(TPolyVerbRec),Handle(aPolyVerbH));
  3032.       clipRgn := NewRgn;
  3033.       GetClip(clipRgn);
  3034.       ClipRect(zeroRect);
  3035.       FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);
  3036.       { Next, the -crude- QuickDraw approximation of the smoothed polygon, }
  3037.       { invisible for PostScript because of PolyIgnore: }
  3038.       SetClip(clipRgn);
  3039.       PicComment(PolyIgnore,0,NIL);
  3040.       polyRgn := NewRgn;                   { ••• See comment 3, below. ••• }
  3041.       OpenRgn;
  3042.       MoveTo(q^[0].h,q^[0].v);
  3043.       FOR i := 1 TO kM DO LineTo(q^[i].h,q^[i].v);
  3044.       CloseRgn(polyRgn);
  3045.       FrameRgn(polyRgn);         { Or FillRgn, if fPolyFill above is TRUE. }
  3046.       PicComment(PolyEnd,0,NIL);
  3047.       DisposHandle(Handle(aPolyVerbH));
  3048.       DisposeRgn(polyRgn);
  3049.       DisposPtr(Ptr(p));
  3050.       DisposPtr(Ptr(q));
  3051.    END;
  3052. Figure 3-Output on Quickdraw printer; Figure 4-Output on PostScript printer
  3053. Additional Comments and Explanations 
  3054. 1.    The fPolyFrame and fPolyFill fields of the TPolyRec record are self-explanatory. The fPolyClose flag is redundant with the PolyClose picture comment, but is included for the convenience of the LaserWriter driver. It is often misunderstood. It does not mean the polygon is being closed automatically, such as with the PostScript closepath operator; instead, it affects the shape of the smooth curve. Figure 4 shows the result for fPolyClose = FALSE; the start and end point of the polygon is distinguished. In the case of fPolyClose = TRUE, all vertices of the polygon are treated in the same manner, and the resulting curve resembles a circle (in this case).
  3055. 2.    The anonymous fields f3..f7 are reserved and should be set to zero (that is, FALSE).
  3056. 3.    The polygon is drawn at the current pen location when the PolyBegin comment is received. 
  3057. 4.    In general (and in this example), you do not need to open a region, collect the line segments in the region, and draw the polygon through FrameRgn. It is demonstrated here only to prepare you for situations where you want to fill the polygon with a pattern. You cannot open a polygon and use FillPoly, because the PostScript driver “owns” the polygon concept at this point and captures—and ignores—all line drawing between the PolyIgnore and PolyEnd comment. Regions do not interfere with polygons, however, and can be used to paint or fill the polygonal shape. 
  3058. Caveats
  3059. PostScript Level 1 has problems with very large polygons (more than about 1000 points). The workaround is to subdivide the large polygon into several smaller ones.
  3060. You cannot combine the polygon picture comments with other comments such as the rotation comments or the DashedLine comment. It’s just another limitation—no comment. 
  3061. Dashed Lines
  3062. Comments:    DashedLine, DashedStop
  3063. PostScript allows applications to draw precisely dashed lines with a given dash pattern in every direction (see the setdash operator, PostScript Language Reference Manual, Second Edition, page 500). The QuickDraw ersatz of setting the pen pattern appears to be awkward at best; the result depends very much on the direction of the line. Coding correctly dashed lines in QuickDraw is quite a hassle and rather clumsy. This is why the DashedLine and DashedStop picture comments have been provided for applications where dashed lines are important and used frequently. Applications can take advantage of these comments when printing to a PostScript printer.
  3064. The DashedLine comment tells the driver that the line drawing instructions following the comment should be dashed according to the parameters in the TDashedLine structure (see the Appendix). These parameters closely correspond to the parameters passed to the PostScript setdash operator. Only the centered field of the TDashedLine structure is not currently supported by the LaserWriter driver. It should be set to 0 in case support for centering is added in the future.
  3065. Unlike the picture comments for text rotation or even polygon smoothing, the DashedLine picture comment should not be supported by a non-PostScript driver. The only way to include representations of dashed lines with and without usage of the DashedLine picture comment is to make the following assumption: If the DashedLine comment is supported, then the printer is a PostScript printer, and the PostScriptBegin/PostScriptEnd bracket may be used to hide the QuickDraw imaging from the printer. Remember that non-PostScript printer drivers must not ignore QuickDraw imaging within PostScriptBegin and PostScriptEnd!
  3066. But we still need a trick to hide the line drawing instructions within the DashedLine – DashedStop bracket from QuickDraw. Here comes the “magic pen mode” to our rescue:
  3067. PROCEDURE DashDemo;
  3068.    CONST
  3069.       magicPen = 23; { the infamous penMode ! }
  3070.       cx = 280;
  3071.       cy = 280;
  3072.       r0 = 200;
  3073.    VAR
  3074.       dashHdl: TDashedLineHdl;
  3075.       i: Integer;
  3076.       a, rad : Extended;
  3077.    BEGIN
  3078.       PenSize(2,2);
  3079.       { First the PostScript picture comment version.  }
  3080.       { The "magic pen mode" 23 makes the line drawing invisible for QuickDraw. }
  3081.       PenMode(magicPen);
  3082.       dashHdl := TDashedLineHdl(NewHandle(SizeOf(TDashedLineRec)));
  3083.       IF dashHdl <> NIL THEN
  3084.          WITH dashHdl^^ DO BEGIN
  3085.             offset := 4;       { just for fun }
  3086.             centered := 0;     { Currently ignored - set to 0. }
  3087.             intervals[0] := 2; { number of interval specs      }
  3088.             intervals[1] := 4; { This means 4 points on ...    }
  3089.             intervals[2] := 6; { ... and 6 points off.         }
  3090.             PicComment(DashedLine, SizeOf(TDashedLineRec), Handle(dashHdl));
  3091.          END;
  3092.       rad := 3.14159 / 180;    { Conversion degrees -> radians. }
  3093.       FOR i := 0 TO 9 DO BEGIN { Draw some dashed lines. }
  3094.          a := i * 20 * rad;
  3095.          MoveTo(cx, cy);
  3096.          Line(round(r0 * cos(a)), - round(r0 * sin(a)));
  3097.       END;
  3098.       PicComment(DashedStop, 0, NIL); { That's enough! }
  3099.       DisposHandle(Handle(dashHdl));
  3100.       PenMode(srcOr);  { No magic any more. }
  3101.       { Now, the QuickDraw version. The PostScript driver must ignore it, }
  3102.       { so we enclose it between PostScriptBegin and PostScriptEnd comments.}
  3103.       PicComment(PostScriptBegin, 0, NIL);
  3104.       PenSize(2,2);
  3105.       FOR i := 0 TO 9 DO BEGIN
  3106.          MoveTo(cx,cy);
  3107.          DashedQDLine(round(r0 * cos(i * 20 * rad)),
  3108.                     - round(r0 * sin(i * 20 * rad)), dashHdl);
  3109.       END;
  3110.       PicComment(PostScriptEnd,0,NIL);
  3111.    END;
  3112. By the way: The DashedQDLine procedure is intentionally missing. It’s not precisely the subject of this Note, and thus, again, is left as a spare-time exercise for the reader.
  3113. Caveat
  3114. As mentioned earlier, the current version of the PostScript LaserWriter driver produces poor results when the DashedLine picture comment is applied to polygons. Just don’t do it!
  3115. Fractional Line Width
  3116. Comment:    SetLineWidth
  3117. QuickDraw’s design is based on a fixed 72-dpi resolution. Even when printing to a high-resolution device, the Printing Manager presents the printing grafPort, corresponding to the printable area of the page, in the integer-valued QuickDraw coordinate system with 72 dpi. Applications can use PrGeneral to image at higher device resolutions (see Inside Macintosh Volume V, page 410), but this is useful mainly for immediate printing. As a consequence, lines are usually always at least 1/72 inch wide, corresponding to the smallest pen size (1,1). For a 300-dpi device like the LaserWriter, this is disappointing.
  3118. The SetLineWidth comment allows an application to set the width of a line to any fractional value. A value of 1/4 approximately corresponds to a “hairline” on a 300 dpi LaserWriter. Curiously (but conveniently), a QuickDraw Point structure is passed in the PicComment’s data handle, the vertical coordinate representing the denominator, and the horizontal coordinate the numerator of the fraction.
  3119. Unfortunately, it is not implemented in all high-resolution QuickDraw printers; and if it is (as in the LaserWriter SC), it works differently than in PostScript printer drivers. Moreover, there is no possibility to include alternative imaging instructions in case SetLineWidth is not supported. While this is not much of a loss for hairlines, it prevents us from using the comment for fractional widths > 1, where the alternative would be to include a PenSize call with rounded arguments. Another drawback may be that, allegedly, there are plotter drivers out there that abuse this comment to set the pen color—clearly an unpleasant situation.
  3120. The difference in the implementation of the SetLineWidth comment between the PostScript LaserWriter driver and the LaserWriter SC appears as soon as SetLineWidth is used for the second time. The PostScript driver keeps an internal line scaling factor; this factor is initialized to 1.0 when a job is started. Each number passed through SetLineWidth is multiplied by the current internal scaling factor to get the effective scaling factor for the pen size. The LaserWriter SC driver, on the other hand, replaces its current scaling factor for the pen size completely by the new value passed through SetLineWidth. In order to support both implementations, you must always use an additional SetLineWidth step in order to reset the PostScript driver line width to 1.0, before scaling to the new value. 
  3121. Example
  3122. Let’s say you have set the line width to 0.25, and want to replace it by a line width of 0.5. The following two SetLineWidth comments will have the desired effect on both PostScript (PS) and QuickDraw (QD) drivers that implement the SetLineWidth comment. You don’t care about the temporary line width of 4.0 on the QuickDraw driver.
  3123.     Current Line Width    Parameter Passed    New Line Width
  3124.     PS driver    QD driver    in SetLineWidth    PS Driver    QD Driver
  3125.     0.25    0.25    4/1    1.0    4.0
  3126.     1.0    4.0    1/2    0.5    0.5
  3127.         
  3128. The following sample code gives the expected results only on a PostScript LaserWriter and on QuickDraw printer drivers that have the SetLineWidth comment implemented.
  3129. PROCEDURE SetNewLineWidth(oldWidth,newWidth: TLineWidth);
  3130.    VAR
  3131.       tempWidthH: TLineWidthHdl;
  3132.    BEGIN
  3133.       tempWidthH := TLineWidthHdl(NewHandle(SizeOf(TLineWidth)));
  3134.       { If tempWidthH = NIL we are screwed anyway. }
  3135.       tempWidthH^^.v := oldWidth.h;
  3136.       tempWidthH^^.h := oldWidth.v;
  3137.       PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));
  3138.       tempWidthH^^ := newWidth;
  3139.       PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));
  3140.       DisposHandle(Handle(tempWidthH));
  3141.    END;
  3142. PROCEDURE LineWidthDemo;
  3143.    CONST
  3144.       y0 = 50;  { topleft of demo }
  3145.       x0 = 50;
  3146.       d0 = 440; { length of horizontal lines }
  3147.       e0 = 5;   { distance between lines }
  3148.       kN = 5;   { number of lines }
  3149.    VAR
  3150.       oldWidth,newWidth: TLineWidth;  { actually a "Point" }
  3151.       i,j,y: Integer;
  3152.    BEGIN
  3153.       PenNormal;
  3154.       y := y0;
  3155.       SetPt(oldWidth,1,1);             { initial linewidth = 1.0 }
  3156.       FOR i := 1 TO 5 DO BEGIN
  3157.          SetPt(newWidth,4,i);
  3158.                   { want to set it to i/4 = 0.25, 0.50, 0.75 ... }
  3159.          SetNewLineWidth(oldWidth,newWidth);
  3160.          MoveTo(x0, y);
  3161.          Line(d0, 0);
  3162.          y := y + e0;
  3163.          oldWidth := newWidth;
  3164.       END;
  3165.    END;
  3166. A Slight Imperfection
  3167. If you experiment with the above code and draw a whole series of hairlines, you will see (depending on the values of e0 and kN) that certain lines appear thicker than they should be. This is due to rasterization effects in PostScript’s scan conversion algorithm when the line width is close to the device pixel size. In many cases, the PostScript LaserWriter driver tries to compensate for this by rounding coordinates to the 300-dpi grid. If you include SetLineWidth (or, by the way, DashedLine) picture comments, however, this does not work. PostScript Level 2 addresses this problem by means of an optional stroke adjustment feature (see the PostScript Language Reference Manual, Second Edition, pages 322 and 515).
  3168. Graphics Rotation
  3169. Comments:    RotateBegin, RotateCenter, RotateEnd
  3170. Like the picture comments discussed earlier in this Note in the section “Text Rotation,” the graphics rotation picture comments provide a method of rotating QuickDraw objects on PostScript devices. Instead of having QuickDraw perform the rotation, the printer driver rotates the entire PostScript coordinate space so that everything drawn between RotateBegin and RotateEnd will be rotated on the printer itself. This includes text drawing! You specify the center of rotation with RotateCenter and the angle of the rotation, together possibly with horizontal or vertical flipping, through the TRotation record (see the interface definitions in the Appendix).
  3171. Unlike text rotation, you must insert the RotateCenter comment and pass the relative offset to the center of rotation before you use the RotateBegin picture comment. The point passed to RotateCenter specifies the offset from the anchor point of the first object drawn after RotateBegin to the desired center of rotation. Once you set up the rotation parameters with RotateCenter and RotateBegin, you can draw the graphics objects you want to rotate.
  3172. Bad news: In order to include a QuickDraw representation of the rotated objects in case the rotation comments are not supported, we have to assume (again) that only PostScript drivers implement these comments. The only way to hide the QuickDraw substitute from the driver is to surround it by PostScriptBegin and PostScriptEnd comments; and, similarly to the DashedLine comment, we need to use the “magic pen mode” (23) to hide the unrotated drawing between RotateBegin and RotateEnd from QuickDraw. The following sample demonstrates this:
  3173. PROCEDURE QDRotatedRect(r: Rect; ctr: Point; angle: Integer);
  3174.    BEGIN
  3175.       { An exercise again - this one is easy ...             }
  3176.       { Rotates the four points of the rectangle by "angle"  }
  3177.       { around the center obtained by adding the point "ctr" }
  3178.       { as offset to r.topLeft, and draws the rotated Rect.  }
  3179.    END;
  3180. PROCEDURE PSRotatedRect(r: Rect; offset: Point; angle: Integer);
  3181. { Does the rectangle rotation for the PostScript LaserWriter driver. }
  3182. { Uses the RotateCenter, RotateBegin and RotateEnd picture comments, }
  3183. { and the "magic" pen mode 23 to hide the drawing from QuickDraw.    }
  3184.    CONST
  3185.       magicPen = 23;
  3186.    VAR
  3187.       rInfo: TRotationHdl;
  3188.       rCenter: TCenterHdl;
  3189.       oldPenMode: Integer;
  3190.    BEGIN
  3191.       rInfo := TRotationHdl(NewHandle(SizeOf(TRotationRec)));
  3192.       rCenter := TCenterHdl(NewHandle(SizeOf(TCenterRec)));
  3193.       IF (rInfo = NIL) OR (rCenter = NIL) THEN DebugStr('NewHandle failed');
  3194.       WITH rInfo^^ DO BEGIN
  3195.          rFlip := 0;
  3196.          rAngle := - angle;
  3197.          rAngleFixed := BitShift(LongInt(rAngle),16);
  3198.       END;
  3199.       WITH rCenter^^ DO BEGIN
  3200.          x := Long2Fix(offset.h);
  3201.          y := Long2Fix(offset.v);
  3202.       END;
  3203.       MoveTo(r.left,r.top);
  3204.       FlushGrafPortState;
  3205.       PicComment(RotateCenter,SizeOf(TCenterRec),Handle(rCenter));
  3206.       PicComment(RotateBegin,SizeOf(TRotationRec),Handle(rInfo));
  3207.       oldPenMode := thePort^.pnMode;
  3208.       PenMode(magicPen);
  3209.       FrameRect(r);
  3210.       PenMode(oldPenMode);
  3211.       PicComment(RotateEnd,0,NIL);
  3212.       DisposeHandle(Handle(rInfo));
  3213.       DisposeHandle(Handle(rCenter));
  3214.    END;
  3215. PROCEDURE RotateDemo;
  3216.    CONST
  3217.       angle = 30;
  3218.    VAR
  3219.       spinRect: Rect;
  3220.       delta: Point;
  3221.    BEGIN
  3222.       SetRect(spinRect,100,100,300,200);
  3223.       WITH spinRect DO SetPt(delta,(right - left) DIV 2,(bottom - top) DIV 2);
  3224.       PenSize(2,2);
  3225.       PenPat(ltGray);
  3226.       FrameRect(spinRect); { show the unrotated square }
  3227.       PenNormal;
  3228.       PSRotatedRect(spinRect,delta,angle);
  3229.  { QuickDraw equivalent of the rotated object, hidden from PostScript driver  }
  3230.  { because of PostScriptBegin and PostScriptEnd }
  3231.       PicComment(PostScriptBegin,0,NIL);
  3232.       QDRotatedRect(spinRect,delta,angle);
  3233.       PicComment(PostScriptEnd,0,NIL);
  3234.    END;
  3235. PostScript Comments
  3236. Comments:    PostScriptBegin, PSBeginNoSave, PostScriptEnd, PostScriptHandle
  3237. The PostScript comments tell the picture interpreter (usually the LaserWriter driver) that the application is going to communicate with the LaserWriter directly using PostScript code instead of QuickDraw. All QuickDraw drawing instructions between the PostScriptBegin and PostScriptEnd picture comments are ignored. The driver sends the PostScript text contained in the PostScriptHandle data to the printer with no preprocessing and no error checking. When the application is finished sending PostScript, the PostScriptEnd comment tells the printer driver to resume normal QuickDraw mode. The driver uses the PostScript save and restore operators to preserve the state of the PostScript interpreter across the section enclosed by PostScriptBegin and PostScriptEnd. Some applications do not want to restore the previous state of the PostScript interpreter after including their PostScript code; for these situations, the PSBeginNoSave comment is a replacement for PostScriptBegin that does not preserve the state. Clearly, this comment should be used with extreme caution.
  3238. Some state information may be stored in global variables, so nesting PostScriptBegin (or PSBeginNoSave) and PostScriptEnd comments is not allowed.
  3239. The PostScriptHandle comment gives developers direct access to PostScript from applications. Instead of having the LaserWriter driver convert QuickDraw calls into the corresponding PostScript code, the application can generate its own PostScript, and transmit it to the printer or include it in a picture through the data handle of the PicComment procedure. The handle contains pure ASCII text; the valid length of the data is specified in the PicComment’s size parameter. Don’t forget to terminate the PostScript text at least with a space character, or better with a carriage return (ASCII $0D), so that it is separated from the following PostScript instructions (either yours, or the printer driver’s).
  3240. You must still use PostScriptBegin (or PSBeginNoSave) and PostScriptEnd around PostScriptHandle comments or the LaserWriter driver will not properly save and restore the PostScript drawing environment. 
  3241. As with all picture comments, the handle you pass belongs to you and you must dispose of it when you’re finished with it.
  3242. PROCEDURE PostScriptLine(s: Str255);
  3243. { A utility procedure to transmit a string of PostScript code through }
  3244. { the PostScriptHandle picture comment to the PostScript printer.     }
  3245. { It should be called only between PostScriptBegin and PostScriptEnd  }
  3246. { picture comments. }
  3247.    VAR
  3248.       h: Handle;
  3249.    BEGIN
  3250.       h := NewHandle(256);
  3251.       IF h = NIL THEN DebugStr('NewHandle failed');
  3252.       BlockMove(@s[1],h^, Length(s));
  3253.       PicComment(PostScriptHandle, Length(s), h);
  3254.       h^^ := 13;
  3255.       PicComment(PostScriptHandle, 1, h); { add a carriage return }
  3256.       DisposeHandle(h);
  3257.    END;
  3258. PROCEDURE PostScriptComments;
  3259.    BEGIN
  3260.       { First, the simple example: }
  3261.       PicComment(PostScriptBegin,0,NIL);
  3262.       PostScriptLine('100 100 moveto 0 100 rlineto 100 0 rlineto ');
  3263.       PostScriptLine('0 -100 rlineto -100 0 rlineto');
  3264.       PostScriptLine('stroke');
  3265.       MoveTo(30,30);
  3266.       DrawString('This text does not appear on PostScript devices');
  3267.       PicComment(PostScriptEnd,0,NIL);
  3268.       { Now, a new PostScript definition you want to keep in the     }
  3269.       { userdict. If you used PostScriptBegin, the definition would  }
  3270.       { be lost when PostScriptEnd is encountered, because the state }
  3271.       { previous to the PostScriptBegin comment would be restored.   }
  3272.       PicComment(PSBeginNoSave,0,NIL);
  3273.       PostScriptLine('userdict begin');
  3274.       PostScriptLine('/myFrameRect {');
  3275.       PostScriptLine('250 250 moveto 0 100 rlineto');
  3276.       PostScriptLine('200 0 rlineto 0 -100 rlineto -200 0 rlineto ');
  3277.       PostScriptLine('stroke } def');
  3278.       PostScriptLine('end');
  3279.       PicComment(PostScriptEnd,0,NIL);
  3280.       { Let's test to see if the definition from above is still avail-}
  3281.       { able. This assumes that no font downloading has occurred.     }
  3282.       PicComment(PostScriptBegin,0,NIL);
  3283.       PostScriptLine('//userdict /myFrameRect get exec ');
  3284.       PicComment(PostScriptEnd,0,NIL);
  3285.    END;
  3286. Caveat
  3287. If you choose to use PostScript directly in your pictures, be very careful not to make assumptions about Apple’s "md" dictionary (essentially the contents of the former LaserPrep file). Otherwise, your pictures will not print correctly with future versions of the PostScript LaserWriter driver. Also, be aware of compatibility problems within the PostScript world, and watch out for printers with PostScript Level 1 and PostScript Level 2 interpreters, and “PostScript-compatible” printers (PostScript clones).
  3288. FormsPrinting Picture Comments
  3289. Comments:    FormsPrinting, EndFormsPrinting
  3290. The FormsPrinting comment tells the PostScript LaserWriter driver not to clear its page buffer after printing a page. EndFormsPrinting turns this mode off. When the page is completed, the application must erase the areas that need to be updated and draw the new information. The graphics that make up the form are drawn only once per page, which may improve performance. Currently, you need to write special printing code for the PostScript LaserWriter driver if you want to use this comment. 
  3291. (More or Less) Obsolete PostScript Picture Comments
  3292. Comments:    SetGrayLevel,
  3293.     TextIsPostScript, ResourcePS, PostScriptFile
  3294. The SetGrayLevel picture comment was designed to provide access to the PostScript setgray operator while still drawing with QuickDraw in black-and-white mode. In practice, this turned out to be not so useful, however. For most drawing operations, the printer driver sets the gray level to match the foreground color currently stored in the printing grafPort, and the effect of the SetGrayLevel comment is often unpredictable. If direct access to the PostScript setgray operator seems nevertheless desirable, it is easy to include the instruction in a PostScriptHandle comment.
  3295. The TextIsPostScript picture comment takes all the text coming through standard QuickDraw text drawing calls (DrawChar, DrawString, DrawText, and anything else that eventually calls the StdText bottleneck), and interprets it as a PostScript program. There is no good reason to use this picture comment, but there is one important reason not to use it: Printer drivers that do not deal with the TextIsPostScript comment will print the PostScript text instead of interpreting it! If you need to transmit pure PostScript code directly to a printer that understands it, use the PostScriptHandle comment, and include a QuickDraw representation for all other printer drivers.
  3296. The ResourcePS picture comment loads PostScript code from a specified resource. The resource file is expected to be open at the time that the ResourcePS comment is used. Under background printing, there are no guarantees the file will still be open when the Printing Manager needs it. For this reason alone, you should forget about this comment. If you want to keep PostScript instructions in a resource, it is easy to write a small routine that loads the resources and sends their contents using the PostScriptHandle comment described earlier in this Note.
  3297. PostScriptFile has the same problems as ResourcePS described above. Basically, the Printing Manager cannot guarantee that the file will be available when it’s needed.
  3298. Appendix: Pascal Interface for Picture Comments
  3299. (File PicComments.p)
  3300. CONST
  3301.    TextBegin = 150;
  3302.    TextEnd = 151;
  3303.    StringBegin = 152;
  3304.    StringEnd = 153;
  3305.    TextCenter = 154;
  3306.    LineLayoutOff = 155;
  3307.    LineLayoutOn = 156;
  3308.    ClientLineLayout = 157;
  3309.    PolyBegin = 160;
  3310.    PolyEnd = 161;
  3311.    PolyIgnore = 163;
  3312.    PolySmooth = 164;
  3313.    PolyClose = 165;
  3314.    DashedLine = 180;
  3315.    DashedStop = 181;
  3316.    SetLineWidth = 182;
  3317.    PostScriptBegin = 190;
  3318.    PostScriptEnd = 191;
  3319.    PostScriptHandle = 192;
  3320.    PostScriptFile = 193;
  3321.    TextIsPostScript = 194;
  3322.    ResourcePS = 195;
  3323.    PSBeginNoSave = 196;
  3324.    SetGrayLevel = 197;
  3325.    RotateBegin = 200;
  3326.    RotateEnd = 201;
  3327.    RotateCenter = 202;
  3328.    FormsPrinting = 210;
  3329.    EndFormsPrinting = 211;
  3330.   
  3331.    tJusNone = 0;           { values for the tJus field of the TTxtPicRec record }
  3332.    tJusLeft = 1;
  3333.    tJusCenter = 2;
  3334.    tJusRight = 3;
  3335.    tJusFull = 4;
  3336.    
  3337.    tFlipNone = 0;         { values for the tFlip field of the TTxtPicRec record }
  3338.    tFlipHorizontal = 1;
  3339.    tFlipVertical = 2;
  3340. TYPE
  3341.    TTxtPicHdl = ^TTxtPicPtr;
  3342.    TTxtPicPtr = ^TTxtPicRec;
  3343.    TTxtPicRec = PACKED RECORD
  3344.                    tJus  : Byte;
  3345.                    tFlip : Byte; 
  3346.                    tAngle: Integer;     { clockwise rotation in degrees 0..360 }
  3347.                    tLine : Byte;        { Unused/Ignored }
  3348.                    tCmnt : Byte;        { reserved }
  3349.                    tAngleFixed: Fixed;  { same as "tAngle" in Fixed precision  }
  3350.                END; { TTxtPicRec }
  3351.    TRotationHdl = ^TRotationPtr;
  3352.    TRotationPtr = ^TRotation;
  3353.    TRotationRec = RECORD
  3354.                     rFlip: Integer;
  3355.                     rAngle: Integer;    { clockwise rotation in degrees 0..360 }
  3356.                     rAngleFixed: Fixed; { same as "rAngle" in Fixed precision  }
  3357.                  END; { TRotationRec }
  3358.    TCenterHdl = ^TCenterPtr;
  3359.    TCenterPtr = ^TCenter;
  3360.    TCenterRec = RECORD  {offset from current pen location to center of rotation}
  3361.                    y: Fixed;
  3362.                    x: Fixed;
  3363.                 END; { TCenterRec }
  3364.    TPolyVerbHdl = ^TPolyVerbPtr;
  3365.    TPolyVerbPtr = ^TPolyVerbRec;
  3366.    TPolyVerbRec = PACKED RECORD
  3367.                      f7,f6,f5,f4, f3,     { reserved }
  3368.                      fPolyClose,          { TRUE = smoothing across endpoint.}
  3369.                      fPolyFill,           { TRUE = Polygon should be filled. }
  3370.                      fPolyFrame: BOOLEAN; { TRUE = Polygon should be framed. }
  3371.                   END;
  3372.    TDashedLineHdl = ^TDashedLinePtr;
  3373.    TDashedLinePtr = ^TDashedLineRec;
  3374.    TDashedLineRec = PACKED RECORD
  3375.                        offset   : SignedByte;  { offset into pattern for }                                   { first dash              }
  3376.                        centered : SignedByte;  { (Ignored)               }
  3377.                        intervals: ARRAY [0..5] { Array of dash intervals }
  3378.                                   OF SignedByte; { intervals[0] = number }
  3379.                     END;                         { of interval specs.    }
  3380.    TLineWidthHdl = ^TLineWidthPtr;
  3381.    TLineWidthPtr = ^TLineWidth;
  3382.    TLineWidth    = Point;  { v = numerator, h = denominator. }
  3383.    TClientLLHdl = ^TClientLLPtr;  { used in the ClientLineLayout picture comment }
  3384.    TClientLLPtr = ^TClientLLRec;
  3385.    TClientLLRec = RECORD
  3386.                      chCount : Integer;  { Apply for so many characters. }
  3387.                      major   : Fixed;    { percentage of line layout error to be }
  3388.                                          { distributed among space characters.   }
  3389.                      spcChar : Integer;  { code of character that is to absorb   }
  3390.                                          { the "major" line layout error         }
  3391.                      minor   : Fixed;    { percentage of intercharacter distrib. }
  3392.                      ulLength: Fixed;    { underline length.                     }
  3393.                   END;
  3394. Further Reference:
  3395. •    PostScript Language Reference Manual, Adobe Systems Inc.
  3396. •    Inside Macintosh, Volumes II, V, and VI
  3397. •    LaserWriter Reference Manual, Addison-Wesley
  3398. •    Macintosh Technical Note M.IM.AppPictComments —    
  3399.         Every Picture [Comment] Tells Its Story, Don’t It?
  3400. •    Macintosh Technical Note M.IM.PictAndPrinting —
  3401.         Pictures and the Printing Manager
  3402. •    develop Issue 3, “Meet PrGeneral” by Pete “Luke” Alexander
  3403. Adobe is a trademark of Adobe Systems Incorporated.
  3404. PostScript is a registered trademark of Adobe Systems Incorporated.
  3405. Every Picture [Comment] Tells Its Story, Don’t It?
  3406. Imaging    M.IM.AppPictComments
  3407. Revised by:         March 1988
  3408. Written by:    Rick Blair    November 1987
  3409. Application-specific picture comment conflict and registration is addressed, along with Developer Technical Support’s method for solving it.
  3410. I will assume that the nature and usefulness of picture comments are already well known. The problem I am addressing is that, as it stands, developers must register their comments with us (Developer Technical Support) or run the risk of using the same comments as those used by Apple or within another third party product.
  3411. The idea here is to provide a “metacomment” which will contain information about which application owns the comment as well as the comment itself:
  3412. ApplicationComment (long comment)    kind = 100  size = n + 6
  3413.     data = application signature (i.e. 'MPNT' for MacPaint) = 4 bytes
  3414.            application “local” kind = 2 bytes
  3415.            comment data = n bytes
  3416. In this way each comment may be specific to an application. It is still up to a developer to publish information about the comments they have defined if they wish them to be understood and used by other programs.
  3417. Previously assigned and registered comments will still be valid. This means that those  defined for the LaserWriter or MacDraw, for instance, will retain their normal meaning.
  3418. Suppose your application (creator = 'MYAP') wanted to define a comment. The appearance of the comment would be as follows (assuming you chose 128 to be the “local” kind for the comment):
  3419.     kind = 100; data = 'MYAP' [4 bytes] + 128 [2 bytes] + additional data
  3420. Further Reference:
  3421. •    QuickDraw
  3422. •    Technical Note M.IM.PictComments — 
  3423.         Optimizing for the LaserWriter—Picture Comments
  3424. QuickDraw’s Internal Picture Definition
  3425. Imagining    M.IM.PictureOpcodes
  3426. Revised by:    Rick Blair    November 1986
  3427.             March 1988
  3428. Written by:    Ginger Jenigan    April 1985
  3429. This technical note describes the internal format of the QuickDraw picture data structure. This revision corrects some errors in the opcode descriptions and provides some examples.
  3430. This technical note describes the internal definition of the QuickDraw picture. The information given here only applies to QuickDraw picture format version 1.0 (which is always created by Macintoshes without Color QuickDraw). Picture format version 2.0 is documented in the Color QuickDraw chapter of Inside Macintosh. This information should not be used to write your own picture bottleneck procedures; if we add new objects to the picture definition, your program will not be able to operate on pictures created using standard QuickDraw. Your program will not know the size of the new objects and will, therefore, not be able to proceed past the new objects. (What this ultimately means is that you can’t process a new picture with an old bottleneck proc.)
  3431. Terms
  3432. An opcode is a number that DrawPicture uses to determine what object to draw or what mode to change for subsequent drawing. The following list gives the opcode, the name of the object (or mode), the associated data, and the total size of the opcode and data. To better interpret the sizes, please refer to page I-91 of the Using Assembly Language chapter of Inside Macintosh. For types not described there, here is a quick list:
  3433.     opcode    byte
  3434.     mode        word
  3435.     point        4 bytes
  3436.     0..255    byte
  3437.     –128..127    signed byte
  3438.     rect        8 bytes
  3439.     poly        10+ bytes (starts with word size for poly (incl. size word)
  3440.     region        10+ bytes (starts with word size for region (incl. size word)
  3441.     fixed point    long
  3442.     pattern    8 bytes
  3443.     rowbytes    word (always even)
  3444.     bit data    rowbytes * (bounds.bottom - bounds.top) bytes
  3445. Each picture definition begins with a picsize (word), then a picframe (rect), and then the picture definition, which consists of a combination of the following opcodes:
  3446. Opcode        Name        Additional Data                Total Size (bytes)
  3447. 00        NOP        none                    1
  3448. 01        clipRgn    rgn                    1+rgn
  3449. 02        bkPat        pattern                    9
  3450. 03        txFont        font (word)                3
  3451. 04        txFace        face (byte)                2
  3452. 05         txMode        mode (word)                3
  3453. 06        spExtra        extra (fixed point)            5
  3454. 07        pnSize        pnSize (point)                5
  3455. 08        pnMode    mode (word)                3
  3456. 09        pnPat        pattern                    9
  3457. 0A        thePat        pattern                    9
  3458. 0B        ovSize        point                    5
  3459. 0C        origin        dh, dv (words)                5
  3460. 0D        txSize        size (word)                3
  3461. 0E        fgColor        color (long)                5
  3462. 0F        bkColor    color (long)                5
  3463. 10        txRatio        numer (point), denom (point)        9
  3464. 11        picVersion    version (byte)    2
  3465. 20         line        pnLoc ( point ), newPt ( point )        9
  3466. 21        line from    newPt ( point )                5
  3467. 22        short line    pnLoc ( point ); dh, dv (-128..127)        7
  3468. 23        short line from    dh, dv (-128..127)            3
  3469. 28         long text    txLoc ( point ), count (0..255), text    6+text
  3470. 29        DH text    dh (0..255), count (0..255), text        3+text
  3471. 2A        DV text    dv (0..255), count (0..255), text        3+text
  3472. 2B        DHDV text    dh, dv (0..255), count (0..255), text    4+text
  3473. 30         frameRect    rect                    9
  3474. 31        paintRect     rect                    9
  3475. 32        eraseRect     rect                    9
  3476. 33        invertRect     rect                    9
  3477. 34        fillRect     rect                    9
  3478. 38         frameSameRect    rect                    1
  3479. 39        paintSameRect     rect                    1
  3480. 3A        eraseSameRect     rect                    1
  3481. 3B        invertSameRect     rect                    1
  3482. 3C        fillSameRect     rect                    1
  3483. 40         frameRRect    rect ( ovalwidth, height; see 1, below )    9
  3484. 41        paintRRect     rect ( ovalwidth, height; see 1, below )    9
  3485. 42        eraseRRect     rect ( ovalwidth, height; see 1, below )    9
  3486. 43        invertRRect         rect ( ovalwidth, height; see 1, below )    9
  3487. 44        fillRRect         rect ( ovalwidth, height; see 1, below )    9
  3488. 48         frameSameRRect    rect                    1
  3489. 49        paintSameRRect     rect                    1
  3490. 4A        eraseSameRRect     rect                    1
  3491. 4B        invertSameRRect     rect                    1
  3492. 4C        fillSameRRect         rect                    1
  3493. Opcode (cont.)    Name             Additional Data            Total Size (bytes)
  3494. 50         frameOval        rect                    9
  3495. 51        paintOval         rect                    9
  3496. 52        eraseOval        rect                    9
  3497. 53        invertOval         rect                    9
  3498. 54        fillOval         rect                    9
  3499. 58         frameSameOval        rect                    1
  3500. 59        paintSameOval         rect                    1
  3501. 5A        eraseSameOval         rect                    1
  3502. 5B        invertSameOval        rect                    1
  3503. 5C        fillSameOval         rect                    1
  3504. 60         frameArc        rect, startAngle, arcAngle            13
  3505. 61        paintArc         rect, startAngle, arcAngle            13
  3506. 62        eraseArc        rect, startAngle, arcAngle            13
  3507. 63        invertArc         rect, startAngle, arcAngle            13
  3508. 64        fillArc             rect, startAngle, arcAngle            13
  3509. 68         frameSameArc        startAngle, arcAngle            5
  3510. 69        paintSameArc         startAngle, arcAngle            5
  3511. 6A        eraseSameArc         startAngle, arcAngle            5
  3512. 6B        invertSameArc        startAngle, arcAngle            5
  3513. 6C        fillSameArc         startAngle, arcAngle            5
  3514. 70        framePoly        poly                    1+poly
  3515. 71        paintPoly        poly                    1+poly
  3516. 72        erasePoly         poly                    1+poly
  3517. 73        invertPoly         poly                    1+poly
  3518. 74        fillPoly         poly                    1+poly
  3519.     
  3520. 78        frameSamePoly         (not yet implemented—same as 70, etc.)    1
  3521. 79        paintSamePoly         (not yet implemented)            1
  3522. 7A        eraseSamePoly         (not yet implemented)            1
  3523. 7B        invertSamePoly        (not yet implemented)            1
  3524. 7C        fillSamePoly        (not yet implemented)            1
  3525. 80        frameRgn        rgn                    1+rgn
  3526. 81        paintRgn        rgn                    1+rgn
  3527. 82        eraseRgn         rgn                    1+rgn
  3528. 83        invertRgn         rgn                    1+rgn
  3529. 84        fillRgn         rgn                    1+rgn
  3530. 88        frameSameRgn         (not yet implemented—same as 80, etc.)    1
  3531. 89        paintSameRgn         (not yet implemented)            1
  3532. 8A        eraseSameRgn         (not yet implemented)            1
  3533. 8B        invertSameRgn        (not yet implemented)            1
  3534. 8C        fillSameRgn        (not yet implemented)            1 
  3535. 90        BitsRect        rowBytes, bounds, srcRect, dstRect, mode,    29+unpacked
  3536.                     unpacked bitData             bitData
  3537. Opcode (cont.)    Name             Additional Data            Total Size (bytes)
  3538. 91        BitsRgn        rowBytes, bounds, srcRect, dstRect, mode,    29+rgn+
  3539.                     maskRgn, unpacked bitData        bitData
  3540. 98        PackBitsRect        rowBytes, bounds, srcRect, dstRect, mode,    29+packed
  3541.                     packed bitData for each row        bitData
  3542. 99        PackBitsRgn        rowBytes, bounds, srcRect, dstRect, mode,    29+rgn+
  3543.                     maskRgn, packed bitData for each row    packed bitData
  3544. A0        shortComment        kind(word)                3
  3545. A1        longComment        kind(word), size(word), data        5+data
  3546. FF        EndOfPicture        none                    1
  3547. Notes
  3548. Rounded-corner rectangles use the setting of the ovSize point (see opcode $0B, above).
  3549. OpenPicture and DrawPicture set up a default set of port characteristics when they start. When drawing occurs, if the user’s settings don’t match the defaults, mode opcodes are generated. This is why there is usually a clipRgn code after the picVersion: the default clip region is an empty rectangle.
  3550. The only savings that the “same” opcodes achieve under the current implementation is for rectangles. DrawPicture keeps track of the last rectangle used and if a “same” opcode is encountered that requests a rectangle, the last rect. will be used (and no rectangle will appear in the opcode’s data).
  3551. This last section contains some Pascal program fragments that generate pictures. Each section starts out with the picture itself (yes, they’re dull) followed by the code to create and draw it, and concludes with a commented hex dump of the picture.
  3552.     {variables used in all examples}
  3553.     VAR
  3554.         err:     OSErr;
  3555.         ph:      PicHandle;
  3556.         h:       Handle;
  3557.         r:       Rect;
  3558.         smallr:  Rect;
  3559.         orgr:    Rect;
  3560.         pstate:  PenState; {are they in the Rose Bowl, or the state pen?}
  3561. I.    {Rounded-corner rectangle}
  3562.     SetRect(r, 20, 10, 120, 175);
  3563.     ClipRect(myWindow^.portRect);
  3564.     ph := OpenPicture(r);
  3565.     FrameRoundRect (r, 5, 4); {r,width,height}
  3566.     ClosePicture;
  3567.     DrawPicture(ph, r);
  3568. 'PICT' (1)  0026 {size}  000A 0014 00AF 0078 {picFrame}
  3569.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3570.     0B 0004 0005 {ovSize point}  40 000A 0014 00AF 0078 {frameRRect
  3571.     rectangle}
  3572.     FF {fin} 
  3573. _______________________________________________________________________________________________
  3574. II.    {Overpainted arc}
  3575.     GetPenState(pstate); {save}
  3576.     SetRect(r, 20, 10, 120, 175);
  3577.     ClipRect(myWindow^.portRect);
  3578.     ph := OpenPicture(r);
  3579.     PaintArc(r, 3, 45); {r,startangle,endangle}
  3580.     PenPat(gray);
  3581.     PenMode(patXor); {turn the black to gray}
  3582.     PaintArc(r, 3, 45); {r,startangle,endangle}
  3583.     ClosePicture;
  3584.     SetPenState(pstate); {restore}
  3585.     DrawPicture(ph, r);
  3586. data 'PICT' (2)  0036 {size}  000A 0014 00AF 0078 {picFrame}
  3587.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3588.     61 000A 0014 00AF 0078 0003 002D {paintArc rectangle,startangle,endangle}
  3589.     08 000A {pnMode patXor — note that the pnMode comes before the pnPat}
  3590.     09 AA55 AA55 AA55 AA55 {pnPat gray}
  3591.     69 0003 002D {paintSameArc startangle,endangle}
  3592.     FF {fin} 
  3593. III.    {CopyBits nopack, norgn, nowoman, nocry}
  3594.     GetPenState(pstate);
  3595.     SetRect(r, 20, 10, 120, 175);
  3596.     SetRect(smallr, 20, 10, 25, 15);
  3597.     SetRect(orgr, 0, 0, 30, 20);
  3598.     ClipRect(myWindow^.portRect);
  3599.     ph := OpenPicture(r);
  3600.     PaintRect(r);
  3601.     CopyBits (myWindow^.portBits, myWindow^.portBits,
  3602.                  smallr, orgr, notSrcXor, NIL); 
  3603.     {note: result BitMap is 8 bits wide instead of the 5 specified by     smallr}
  3604.     ClosePicture;
  3605.     SetPenState(pstate); {restore the port's original pen state}
  3606.     DrawPicture(ph, r);
  3607. data 'PICT' (3)  0048 {size}  000A 0014 00AF 0078 {picFrame}
  3608.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3609.     31 000A 0014 00AF 0078 {paintRect rectangle}
  3610.     90 0002 000A 0014 000F 001C {BitsRect rowbytes bounds (note that bounds                         is wider than smallr)}
  3611.     000A 0014 000F 0019 {srcRect}
  3612.     0000 0000 0014 001E {dstRect}
  3613.     00 06 {mode=notSrcXor}
  3614.     0000 0000 0000 0000 0000 {5 rows of empty bitmap (we copied from a
  3615.                                 still-blank window)}
  3616.     FF {fin}
  3617. Further Reference:
  3618. •    QuickDraw
  3619. •    Color QuickDraw
  3620. •    Using Assembly Language
  3621. •    Technical Note #59—Pictures and Clip Regions
  3622. Picture Utility Q&As
  3623. Imaging    M.IM.PictUtil.Q&As
  3624. Revised by:    Developer Support Center    October 1992
  3625. Written by:    Developer Support Center    October 1990
  3626. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  3627. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  3628. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  3629. GetPictInfo and QuickTime compressed PICT files
  3630. Written:    2/24/92
  3631. Last reviewed:    8/1/92
  3632. Is it my imagination, or does GetPictInfo return a bit depth of 1 on QuickTime compressed PICT files?
  3633. ___
  3634. Yep! I think this is what happens: The PUP (Picture Utility Package) does not know of the QuickTime Compressed Pixmap opcode (0x8200) and it just skips over the opcode’s data; then it finds the PacksBitRect opcode containing the black-and-white pseudo-alert that you get when you draw the picture in a machine that does not have QuickTime installed, and this is what GetPictInfo reports back.
  3635. Trivia: when QuickTime is installed it displays the compressed image and then ignores the following PacksBitRect since QuickTime knows it is only the b&w warning.
  3636. NewPalette doesn’t use CTab2Palette to create a palette
  3637. Written:    3/12/92
  3638. Last reviewed:    8/1/92
  3639. I am using the Picture Utilities package to extract the color table from a picture. After getting the color table, I use NewPalette to construct a palette from the color table (usage = tolerant, tolerance = 0). After doing this, the RGB values in the palette don’t always exactly match the RGB values in the source color table, causing my program to fail. If I use NewPalette without a source color table, and then use CTab2Palette to copy the colors over (again with usage = tolerant, tolerance = 0), the colors match exactly.
  3640. ___
  3641. It turns out that NewPalette does not use CTab2Palette, but copies the RGB fields in a strange fashion that is causing the problems you are seeing.
  3642. NewPalette copies the high byte in each color table RGB entry into the high byte, as well as the low byte of the corresponding palette entry. Thus, if the color table entry for red was $F000, it becomes $F0F0. This of course makes no difference to QuickDraw since the low byte is not displayed, but if your program expects the low byte to match, then that is where your problem exists.
  3643. It is unfortunate that CTab2Palette is different. It turns out that CTab2Palette does not copy the high byte into the low byte unless the pmAnimated bit is set in the usage.
  3644. So, the best solution for your code is not to compare the entire RGB value when comparing colors, but rather to compare the high byte of each RGB component separately. If this is not possible, the next best solution is for you to go ahead and use the workaround that you’ve already discovered with CTab2Palette.
  3645. It’s unlikely that the the Palette Manager is going to change in the future for something like this. In fact, we would almost call it a “feature” since other developers may even depend on it.
  3646. Spooling PixMaps to disk
  3647. Written:    6/10/91
  3648. Last reviewed:    10/22/91
  3649. Do you have sample code for spooling PixMaps to disk in PICT format? Should I write the PICT opcodes to the file myself?
  3650. ___
  3651. Apple recommends that you do not try to write the PICT opcodes yourself. Instead, replace the PutPicProc bottleneck proc, as shown in the Color QuickDraw chapter of Inside Macintosh Volume V on page V-89.
  3652. Two additional samples can be found in the sample code contained in the Developer CDs. Look for: “Tools & Apps: Graphics and Imaging: PICT Stuff.” One is a program and the other is an FKEY; both dump the main screen to disk as a PICT. The FKEY is a more complete sample in the sense that it works in black and white as well as Macintosh color computers, but the other is a smaller and simpler sample.
  3653. Getting the color usage from a picture under System 6
  3654. Written:    6/8/92
  3655. Last reviewed:    9/15/92
  3656. Do you know how I can obtain the color table of a picture when using a system version that happens to be less than 7.0? The Picture Utilites package seems to be only implemented in System 7.0.
  3657. ___
  3658. You’re correct; the Picture Utilities package is implemented only under System 7. However, it’s possible to write code to duplicate its functionality under System 6. Basically, what you want to do is parse a picture, looking at the colors used for the different objects. How you deal with the colors is up to you.
  3659. What you do is replace the QuickDraw bottlenecks in a GrafPort with procedures of your own; in all the bottlenecks for QuickDraw primitives, you can just record the current color as having been used for an object. When you get a StdBits opcode, you’ll have to parse the pixmaps, looking through the image and recording all the colors used. As a shortcut, you could just record all the colors in the color table of the pixmap, if it's an indexed pixel image. After collecting this list of colors and any information on how often they are used, it’s up to you to boil this down into useful information, depending on how you want to use it.
  3660. Pictures and Clip Regions
  3661. Imaging    M.IM.PictClipRegions
  3662. Revised by:         March 1988
  3663. Written by:    Jennifer Jernigan    January 1986
  3664. This note describes a problem that affects creation of QuickDraw pictures.
  3665. When a GrafPort is created, the fields in the GrafPort are given default values; one of these is the clip region, which is set to the rectangle (–32767, –32767, 32767, 32767). If you create a picture, then call DrawPicture with a destination rectangle that is not the same size as the picFrame without ever changing the default clip region, nothing will be drawn.
  3666. When the picture frame is compared with the destination rectangle and the picture is scaled, the clip region is scaled too. In the process of scaling, the clip region you end up overflows and becomes empty, and your picture doesn’t get drawn. If you call ClipRect(thePort^.portRect) before you record the picture, the picture will be drawn correctly. The clipping on the destination port when playing back the picture is irrelevant: once a picture is incorrectly recorded, it is too late.
  3667. Further Reference:
  3668. •    QuickDraw
  3669. Plotting Small Icons
  3670. Imaging    M.IM.SmallIcons
  3671. Revised by:    James Beninghaus    October 1989
  3672. Written by:    James Beninghaus & Dennis Hescox    August 1989
  3673. This Technical Note discusses the 'SICN' resource format and how to plot one in a GrafPort.
  3674. Changes since August 1989:  Corrected errors in the Pascal code and spruced up the rest.
  3675. Introduction
  3676. Apple first introduced the 'SICN' resource so that the Script Manager could represent which country specific resources are installed in the system by displaying a small icon in the upper right corner of the menu bar.  You can pass a 'SICN' resource to the Notification Manager or Menu Manager, and they will draw it for you automatically—you should continue to let them do so.  However, if you want to draw a small icon in your application’s window, then this Note can help.
  3677. What does a 'SICN' look like?  Following is a 'SICN' representation of a dogcow to help answer this question:
  3678. SICN'            FatBits
  3679. There is reason to believe that this representation is actually a baby dogcow.  Due to the protective nature of parent dogcows, young dogcows are rarely seen.  This one was spotted during a DTS meeting after it drew attention to itself by crying “moo! woof!”.  (Note that this dogcow said “moo! woof!” because it was immature; adult dogcows naturally say, “Moof!”.)
  3680. 'SICN' Resource
  3681. A 'SICN' resource contains any number of small icon bit images.  Each small icon in a 'SICN' list describes a 16 by 16 pixel image and requires 32 bytes of storage.  Like an 'ICN#' resource, there is no count of the number of icons stored in a 'SICN'.  The following 'SICN' resource, in MPW Rez format, contains two small icons:
  3682.     resource 'SICN' (1984, "clarus") {
  3683.         {    /* array: 2 elements */
  3684.             $"00 48 00 B4 00 84 40 52 C0 41 A0 81 9F 8E 8F 18"
  3685.             $"40 18 40 18 47 88 48 48 48 48 44 44 3C 3C 00 00",
  3686.             $"00 48 00 FC 00 FC 40 7E C0 7F E0 FF FF FE FF F8"
  3687.             $"7F F8 7F F8 7F F8 78 78 78 78 7C 7C 3C 3C 00 00"
  3688.         }
  3689.     };
  3690. The Right Tools for the Job
  3691. The Macintosh Toolbox interfaces do not describe all the necessary data structures needed to work with 'SICN' resources.  As shown in the following example, defining the 'SICN' type as an array of 16 short integers and the handles and pointers to this array type make life much easier.
  3692. Pascal
  3693. TYPE
  3694.        SICN        = ARRAY[0 .. 15] of INTEGER;
  3695.        SICNList    = ARRAY[0 .. 0] of SICN;
  3696.        SICNPtr     = ^SICNList;
  3697.        SICNHand    = ^SICNPtr;
  3698. C
  3699. typedef    short       SICN[16];
  3700. typedef    SICN        *SICNList;
  3701. typedef    SICNList    *SICNHand;
  3702. The Missing Count
  3703. The 'SICN' resource does not provide a count to indicate the number of small icons contained within; however, you can easily determine this number by dividing the total size of the resource by the size of a single small icon.
  3704. Pascal
  3705. CONST
  3706.        mySICN      = 1984;
  3707. VAR
  3708.        theSICN     : SICNHand;
  3709.        theSize     : LONGINT;
  3710.        theCount    : LONGINT;
  3711.        theIndex    : LONGINT;
  3712. theSICN := SICNHand(GetResource('SICN', mySICN));
  3713. IF (theSICN <> NIL) THEN BEGIN
  3714.        theSize := GetHandleSize(Handle(theSICN));
  3715.        theCount := theSize DIV sizeof(SICN);
  3716. END;
  3717. C
  3718. #define mySICN         1984
  3719. SICNHand   theSICN;
  3720. long       theSize;
  3721. long       theCount;
  3722. long       theIndex;
  3723. theSICN = (SICNHand) GetResource('SICN', mySICN);
  3724. if (theSICN) {
  3725.        theSize = GetHandleSize((Handle)theSICN);
  3726.        theCount = theSize / sizeof(SICN);
  3727. }
  3728. The Plot 'SICN's
  3729. The example procedure PlotSICN draws one small icon of a 'SICN' resource.  It takes the handle from theSICN and the position in the list from theIndex within the rectangle theRect of the current GrafPort.
  3730. Following is an example call to PlotSICN which plots all the small icons in a resource into the same rectangle:
  3731. Pascal
  3732. SetRect(theRect, 0, 0, 16, 16);
  3733. FOR theIndex := 0 TO theCount-1 DO
  3734.        PlotSICN(theRect, theSICN, theIndex);
  3735. C
  3736. SetRect(&theRect, 0, 0, 16, 16);
  3737. for (theIndex = 0; theIndex < theCount ; ++theIndex)
  3738.        PlotSICN(&theRect, theSICN, theIndex);
  3739. Because PlotSICN uses _CopyBits and _CopyBits can move memory, you should lock the handle to the 'SICN' once the resource is loaded.  Notice that the PlotSICN procedure dereferences the 'SICN' handle, adds an offset, and copies the resulting value.  If the 'SICN' list moves in memory at this time, the bitmap’s baseAddr is useless.
  3740. To play it safe, PlotSICN saves a copy of the master pointer flags associated with the relocatable block, locks the block with a call to _HLock, and restores the flags after calling _CopyBits.  You should never examine, set, or clear these flags directly; you should always use the routines which are provided by the Memory Manager and Resource Manager.  Note that it is not necessary to check the value of the flag after getting it.
  3741. Pascal
  3742. PROCEDURE PlotSICN(theRect: Rect; theSICN: SICNHand; theIndex : INTEGER);
  3743. VAR
  3744.        state       : SignedByte;    { we want a chance to restore original state }
  3745.        srcBits     : BitMap;    { built up around 'SICN' data so we can _CopyBits }
  3746. BEGIN
  3747.        { check the index for a valid value }
  3748.        IF (GetHandleSize(Handle(theSICN)) DIV sizeof(SICN)) > theIndex THEN
  3749.        BEGIN
  3750.            { store the resource's current locked/unlocked condition }
  3751.            state := HGetState(Handle(theSICN));
  3752.            { lock the resource so it won't move during the _CopyBits call }
  3753.            HLock(Handle(theSICN));
  3754.            { set up the small icon's bitmap }
  3755.            {$PUSH}
  3756.            {$R-}            { turn off range checking }
  3757.            srcBits.baseAddr := Ptr(@theSICN^^[theIndex]);
  3758.            {$POP}
  3759.            srcBits.rowBytes := 2;
  3760.            SetRect(srcBits.bounds, 0, 0, 16, 16);
  3761.            { draw the small icon in the current grafport }
  3762.            CopyBits(srcBits,thePort^.portBits,srcBits.bounds,theRect,srcCopy,NIL);
  3763.            { restore the resource's locked/unlocked condition }
  3764.            HSetState(Handle(theSICN), state);
  3765.        END;
  3766. END;
  3767. C
  3768. void PlotSICN(Rect *theRect, SICNHand theSICN, long theIndex) {
  3769.        auto    char    state;    /* saves original flags of 'SICN' handle */
  3770.        auto    BitMap    srcBits;    /* built up around 'SICN' data so we can _CopyBits */
  3771.        /* check the index for a valid value */
  3772.        if ((GetHandleSize(Handle(theSICN)) / sizeof(SICN)) > theIndex) {
  3773.            /* store the resource's current locked/unlocked condition */
  3774.            state = HGetState((Handle)theSICN);
  3775.            /* lock the resource so it won't move during the _CopyBits call */
  3776.            HLock((Handle)theSICN);
  3777.            /* set up the small icon's bitmap */
  3778.            srcBits.baseAddr = (Ptr) (*theSICN)[theIndex];
  3779.            srcBits.rowBytes = 2;
  3780.            SetRect(&srcBits.bounds, 0, 0, 16, 16);
  3781.            /* draw the small icon in the current grafport */
  3782.            CopyBits(&srcBits,&(*qd.thePort).portBits,&srcBits.bounds,theRect,srcCopy,nil);
  3783.            /* restore the resource's locked/unlocked condition */
  3784.            HSetState((Handle) theSICN, state);
  3785.        }
  3786. }
  3787. That Was Easy
  3788. Now that you’ve seen it done, it looks pretty easy.  With minor modifications, some of the techniques in this Note could also be used to plot a bitmap of any dimension.
  3789. Further Reference:
  3790. •    Inside Macintosh, Volume I, QuickDraw
  3791. •    Inside Macintosh, Volume I, Toolbox Utilities
  3792. •    Inside Macintosh, Volume IV, The Memory Manager
  3793. •    Technical Note M.IM.OffscreenBitMap —
  3794.          Drawing Into an Off-Screen BitMap
  3795. •    Technical Note M.IM.DrawingIcons —
  3796.          Drawing Icons
  3797. Principia Off-Screen Graphics Environments
  3798. Imaging    M.IM.PrincipiaOffScreen
  3799. Updated by:    Forrest Tanaka    March 1992
  3800. Written by:    Forrest Tanaka    October 1991
  3801. Inspired by:    Jim Friedlander, Rick Blair, and Rich Collyer
  3802. Using Color QuickDraw to draw off screen is a common requirement of applications and other kinds of programs that run on the Macintosh. This Note discusses what Color QuickDraw needs in a graphics environment and how to create one for off-screen drawing. A brief discussion of GWorlds, which are off-screen graphics environments that are set up by the system, is given to help you decide whether to use them or the do-it-yourself techniques described in this Note for setting up an off-screen graphics environment. The author’s intent is to provide concepts and routines for creating an off-screen graphics environment, and also to explain why existing routines for off-screen drawing act as they do.
  3803. Many, many thanks go to Guillermo Ortiz, Konstantin Othmer, Bruce Leak, and Jon Zap for all their expertise on this subject, Rich Collyer, Rick Blair, and Jim Friedlander for paving the way, and especially to all people who inspired this update by asking great off-screen drawing questions.
  3804. Changes since October 1991:  A very embarrassing bug was found in CreateOffScreen and UpdateOffScreen. If you try to create a 16- or 32-bit off-screen graphics environment, you’ll just get a paramErr. It won’t do that now.
  3805. Off-Screening
  3806. The Macintosh, as with every other CPU ever made by Apple, has memory-mapped video. That is, what you see on the screen is just the visual representation of a part of memory that’s reserved for the video hardware (that’s stretching the truth just a bit in the case of the text screens of the original Apple computer, the Apple II line, and the Apple III because there’s also a character generator in those, but the overall process still looks roughly the same). If you change the contents of a memory location in this part of memory, then you’ll see the corresponding location on the screen change when the video hardware draws the next frame or field of video. The resident raster graphics package, QuickDraw in the case of the Macintosh, draws images by stuffing the right values into the right places in the part of memory reserved for the video display. The resulting image on the screen looks like a line or perhaps an oval if you asked QuickDraw to draw a line or an oval, or it could be an entire complex image if you asked QuickDraw to draw one. This is normal, on-screen drawing.
  3807. Because video memory is a part of RAM just like any other part of RAM in the memory map of the Macintosh (or almost like; video memory might exist on a NuBus™ video card, but it’s still RAM), QuickDraw can be told to draw into a part of memory that isn’t reserved for the video hardware, maybe into a part of your own application’s heap. When you tell QuickDraw to draw into a part of memory that’s not reserved for the video hardware, you can’t see any of the results. This is off-screen drawing. There are plenty of perfectly good reasons to do this, such as providing storage for a paint-style document or to smoothly animate an image, but the assumption here is that you have a perfectly good reason to do this so you’re more interested in the “how” of it instead of the “why” of it. If you need to know why, there are several books that cover off-screen drawing and the perfectly good reasons to do such a thing. A good place to start is Scott Knaster’s book, Macintosh Programming Secrets, referenced at the end of this Note.
  3808. This Note is divided into these major sections:
  3809. • The introduction is the part that you’re reading now.
  3810. • “The Building Blocks” provides an overview of the data structures that you need to tell Color QuickDraw to draw off screen.
  3811. • “Building the Blocks” discusses the construction and initialization of these data structures.
  3812. •    “Playing With Blocks” shows an example of the use of these structures to draw off screen.
  3813. •    “Put That Checkbook Away!” discusses some variations of these techniques to handle off-screen drawing for special cases.
  3814. •    “The GWorld Factor” provides a brief overview of GWorlds, how to use them, and how they compare and contrast to the manual techniques that are described in most of this Note.
  3815. Those of you who aren’t quite sure whether to use GWorlds or the do-it-yourself techniques might want to skip ahead for a moment to “The GWorld Factor” just in case doing it yourself is a waste of time. In any case, it’s a good idea to read this whole Note because the concepts are mostly the same whether you’re using GWorlds or not. GWorlds just make the process a lot easier, and they let you take advantage of the 8•24 GC video card. But, we’re not in that section of the Note yet.
  3816. The Building Blocks
  3817. Before you can tell QuickDraw to draw off of the screen, you’ll need to build three major data structures: a CGrafPort, a PixMap, and a GDevice. You’ll also need a couple of tables that define the colors involved with drawing to and copying from the off-screen image: the color table and the inverse table. Of course, you’ll need the pixel image itself, which is often called the “pixel buffer” or the “image buffer” or the “off-screen buffer” or just “the buffer.” It’s always called the “pixel image” in this Note. It doesn’t necessarily buffer anything anyway.
  3818. The CGrafPort
  3819. A CGrafPort describes a drawing environment, and it’s the color version of the GrafPort structure that’s described on pages 147 through 155 in the QuickDraw chapter of Inside Macintosh Volume I. The drawing environment consists of, among other things, the size and location of the graphics pen, the foreground and background colors to use when something is drawn, the pattern to use, the region to clip all drawing to, and the portion of a pixel image that the CGrafPort logically exists in. Any initialized CGrafPort or GrafPort can be set as the current port through the _SetPort routine. The current port is a set of parameters that are implicitly passed to most QuickDraw routines.
  3820. The most important reason to build a new CGrafPort when you draw off screen rather than using an existing CGrafPort is so that switching between drawing to an off-screen graphics environment and drawing to one or more windows (each of which is an extended GrafPort or CGrafPort structure) on the screen is very easy. Some people use just one CGrafPort to share between on-screen and off-screen graphics environments, and switch their PixMap structures to switch between drawing on screen and drawing off screen. That does work, but if the off-screen and on-screen graphics environments have a different clipRgn, visRgn, pen characteristic, portRect, or any other characteristics that are different, then those must be switched at that time too. If you instead create a CGrafPort that’s dedicated to one graphics environment, then a simple call to _SetPort effectively switches all these things for you at once. That’s why every window on the screen comes with its own port. A simple call to _SetPort switches between the characteristics of each window even if each window has radically different drawing characteristics.
  3821. The CGrafPort data structure is more completely described in the “Color QuickDraw” chapter of Inside Macintosh Volume V, pages 49 through 52, and in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-12 through 16-13.
  3822. The PixMap
  3823. A pixel image alone is just a formless blob of memory. Pixel maps, defined by the PixMap structure, describe pixel images, giving them a form and structure that’s suitable for Color QuickDraw to draw into them and copy from them. The PixMap structure tells you the dimensions and location in memory of the pixel image, its coordinate system, and the depth and format of the pixels. Pixel maps that describe indexed-color pixel images additionally describe the colors that are represented by the values of the pixels in the pixel image. This is done through the color table, also known as the color look-up table or CLUT. Color tables are attached to pixel maps through their pmTable field. Direct-color pixel images have pixel values that describe their own colors, and so color tables aren’t needed for those.
  3824. The PixMap structure is described in the “Color QuickDraw” chapter of Inside Macintosh Volume V, pages 52 through 55, and in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-11 through 16-12. The concept of direct-color and indexed-color pixels is described in this same chapter on pages 16-16 through 16-18, and also in the “Color QuickDraw” chapter of the same volume on pages 17-4 through 17-10.
  3825. The GDevice
  3826. Graphics devices, defined by the GDevice structure, describe color environments. They’re the most misunderstood data structure when it comes to off-screen graphics environments for three major reasons: first, they’re not originally documented as being relevant to humans; second, they look as though they’re only for screens; and third, it looks as though color tables describe color environments. We can dispose of these myths here: graphics devices are documented as being useful to humanity in this Note at least; they’re critically important for both on-screen and off-screen drawing; and color tables describe the colors in pixel images, not color environments.
  3827. What’s all this about color environments? In theory, there are virtually three hundred trillion colors available with Color QuickDraw through the 48-bit RGBColor record. In reality, there are never this many colors available, and in fact there might be only two. Color QuickDraw maps the theoretical color that you specify to the pixel value of the closest available color in the current color environment. This can be done with a color table, but that’s not very efficient. Finding the closest available color to an RGBColor in a color table means searching the entire color table for that one closest color. If that’s done just once, then performance isn’t much of an issue, but if it’s done many times, the performance hit could be significant. A very bad case of this is _CopyBits, where every pixel value in the source image is converted to an RGBColor by looking it up in the color table of the source PixMap. If the color table of the destination PixMap had to be searched to find the closest available color for every pixel in the source PixMap, then the performance of even the most straightforward _CopyBits call could be a lot slower than it has to be.
  3828. To avoid this performance hit, the current GDevice provides an inverse table and a device type which are used to determine the available set of colors. Inverse tables are anticolor tables. Where color tables give you a color for a given pixel value, inverse tables give you a pixel value for a given color. Every conceivable color table has a corresponding conceivable inverse table, just as every positive real number has a corresponding negative real number, or every Mr. Spock has a corresponding Mr. Spock with a goatee. The device type specifies whether the color environment uses the indexed-color, fixed-color, or direct-color model. In the direct-color model, the inverse table is empty. Only the indexed-color and direct-color models are described in this Note.
  3829. When you specify a color in an indexed-color environment, Color QuickDraw takes the RGBColor specification and converts it into a value that can be used as an index into the inverse table of the current GDevice. To do this conversion, Color QuickDraw takes the top few significant bits of each color component and combines them into part of a 16-bit word, blue bits in the least significant bits, green bits right above it, and the red bits right above green bits. Any unused bits are in the most significant bits of the 16-bit word. The resulting 16-bit word is used as an index into the inverse table. The value in the inverse table at that index is the pixel value which best represents that color in the current color environment. The number of bits of each component that are used is determined by what’s called the “resolution” of the inverse table. Almost always, the resolution of an inverse table is four bits, meaning the most significant four bits of each component are used to form the index into the inverse table. Figure 1 shows how an RGBColor record is converted to an index into an inverse table when the inverse-table resolution is four.
  3830. Figure 1  Conversion of RGBColor Record to Inverse-Table Index
  3831. The same process is used when _CopyBits is called with an indexed-color destination. Each pixel in the source pixel image is converted to an RGBColor either by doing a table look-up of the source pixel map’s color table if the source pixel image uses indexed colors, or by expanding the pixel value to an RGBColor record if the source pixel image uses direct colors. The resulting RGBColor is then used to look up a pixel value in the inverse table of the current GDevice, and this pixel value is put into the destination pixel image.
  3832. If you specify a color in a direct-color environment, then the resulting RGBColor is converted to a direct pixel value by the processes that are shown on pages 17-6 through 17-9 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI.
  3833. Usually, inverse-table look-up involves an extra step to find what are called “hidden colors” using proprietary information that’s stored at the end of the inverse table. With an inverse-table resolution of four, only 16 shades of any particular component can be distinguished, and that’s often not enough. An inverse table with a resolution of five is much larger, but it still only gives you 32 shades of any component. Hidden colors are looked up after the normal inverse-table look-up to give a much more accurate representation of the specified color in the current color environment than the inverse-table look-up alone can produce. Sometimes, most notably when the arithmetic transfer modes are used or if dithering is used, the hidden colors are ignored.
  3834. When a new color table is assigned to a PixMap or when its existing color table is modified, then a new corresponding inverse table should be generated for the GDevice that’ll be used when drawing into that environment. Normally, this happens automatically without you having to do any more than inform Color QuickDraw of the change. This is described in more detail in  “Changing the Off-Screen Color Table”  later in this Note.
  3835. Graphics devices are documented in the “Graphics Devices” chapter of Inside Macintosh Volume VI which supersedes the “Graphics Devices” chapter of Inside Macintosh Volume V. They’re also discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-13 through 16-14. The inverse-table mechanism is described in the “Color Manager” chapter of Inside Macintosh Volume V, pages 137 through 139.
  3836. All Together Now
  3837. There are a lot of different ways to put the three structures together, and this Note discusses the architecture that’s shown in Figure 2. This architecture is  useful when you want a simple, atomic, off-screen graphics environment.
  3838. Figure 2  Relationships Between Structures for Off-Screen Drawing
  3839. Notice that there’s no way to get to the GDevice from the CGrafPort, nor is there a way to get to the CGrafPort from the GDevice, though the PixMap can be found through either one. Your application must keep track of both the CGrafPort and the GDevice.
  3840. Building the Blocks
  3841. As with just about any algorithm, there are many ways to put the different structures together that form an off-screen graphics environment. This section covers just one way to build the architecture that’s shown in Figure 2.
  3842. Building the CGrafPort
  3843. The CGrafPort structure is the easiest one to put together because the _OpenCPort routine initializes so many of the fields of the CGrafPort structure for you. It also allocates and initializes the structures that are attached to every CGrafPort, such as the visRgn, clipRgn, grafVars handle, and so forth. Most of these are initialized with values that are fine for general purposes, but the visRgn, clipRgn, and portRect fields should be set to the desired boundary rectangle of the off-screen graphics environment. What follows is an overview of each of the fields that you have to worry about when you’re setting up a CGrafPort for drawing off screen.
  3844. portPixMap    handle to the off-screen PixMap. _OpenCPort initializes this field to a copy of the PixMap that’s attached to the gdPMap field of the current GDevice. An overview of setting up this PixMap for drawing off screen is given in  “Building the PixMap” later in this Note.
  3845. portRect    specifies the rectangular area of the associated pixel image that this CGrafPort controls. This field should be set to the desired rectangular area of the off-screen image because _OpenCPort doesn’t necessarily initialize it to this size. Usually, the top-left corner of this rectangle has the coordinates (0, 0), but not necessarily so.
  3846. visRgn    handle to the region that specifies the visible area into which you can draw. _OpenCPort doesn’t necessarily initialize it to the size of the off-screen image, so it should be set to the same size and coordinates as the portRect and left at that. This field is more important for windows because parts of them can be hidden by other windows.
  3847. clipRgn    handle to the region that specifies the logical area into which you can draw. _OpenCPort initializes it to cover the entire QuickDraw coordinate plane. It’s usually a good idea to set it to the same size and coordinates as the portRect to avoid problems if the clipRgn is scaled or translated, which causes its signed integer coordinates to overflow and turn it into an empty region. One of the most common cases of this occurs when a picture that’s created in this CGrafPort is drawn into a destination rectangle that’s any larger than or translated from the original picture frame. Everything in the picture, including the clip region, is scaled to fit the destination rectangle. If the clip region covers the entire QuickDraw coordinate plane, then its coordinates overflow their signed integer bounds, and the clip region becomes logically empty. The result is that nothing is drawn.
  3848. The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment, given a boundary rectangle, pixel depth, and color table, and it returns a new off-screen CGrafPort and GDevice, along with an error code. The desired pixel depth in bits per pixel is given in the depth parameter. If the pixel depth is eight or less, then an indexed-color graphics environment is created and a color table is required in the colors parameter. If the pixel depth is 16 or 32 bits per pixel and 32-Bit QuickDraw is available, then a direct-color graphics environment is created and the colors parameter is ignored. If 32-Bit QuickDraw isn’t available, then a pixel depth of 16 or 32 bits per pixel results in CreateOffScreen doing nothing more than returning a parameter error. A description of CreateOffScreen is given following the listing.
  3849. MPW Pascal Listing 1
  3850. FUNCTION CreateOffScreen(
  3851.    bounds:         Rect;       {Bounding rectangle of off-screen}
  3852.    depth:          Integer;    {Desired number of bits per pixel in off-screen}
  3853.    colors:         CTabHandle; {Color table to assign to off-screen}
  3854.    VAR retPort:    CGrafPtr;   {Returns a pointer to the new CGrafPort}
  3855.    VAR retGDevice: GDHandle    {Returns a handle to the new GDevice}
  3856.    ): OSErr;
  3857.    CONST
  3858.       kMaxRowBytes = $3FFE; {Maximum number of bytes in a row of pixels}
  3859.    VAR
  3860.       newPort:     CGrafPtr;     {Pointer to the new off-screen CGrafPort}
  3861.       newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}
  3862.       newDevice:   GDHandle;     {Handle to the new off-screen GDevice}
  3863.       qdVersion:   LongInt;      {Version of QuickDraw currently in use}
  3864.       savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}
  3865.       savedState:  SignedByte;   {Saved state of color table handle}
  3866.       bytesPerRow: Integer;      {Number of bytes per row in the PixMap}
  3867.       error:       OSErr;        {Returns error code}
  3868. BEGIN
  3869.    (* Initialize a few things before we begin *)
  3870.    newPort := NIL;
  3871.    newPixMap := NIL;
  3872.    newDevice := NIL;
  3873.    error := noErr;
  3874.    (* Save the color table’s current state and make sure it isn’t purgeable *)
  3875.    IF colors <> NIL THEN
  3876.       BEGIN
  3877.          savedState := HGetState(Handle(colors));
  3878.          HNoPurge(Handle(colors));
  3879.       END;
  3880.    (* Calculate the number of bytes per row in the off-screen PixMap *)
  3881.    bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  3882.    (* Get the current QuickDraw version *)
  3883.    error := Gestalt(gestaltQuickdrawVersion, qdVersion);
  3884.    error := noErr;
  3885.    (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)
  3886.    IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR
  3887.          (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN
  3888.       BEGIN
  3889.          (* Maximum number of bytes per row is 16,382; make sure within range *)
  3890.          IF bytesPerRow <= kMaxRowBytes THEN
  3891.             BEGIN
  3892.                (* Make sure a color table is provided if the depth is indexed *)
  3893.                IF depth <= 8 THEN
  3894.                   IF colors = NIL THEN
  3895.                      (* Indexed depth and clut is NIL; is parameter error *)
  3896.                      error := paramErr;
  3897.             END
  3898.          ELSE
  3899.             (* # of bytes per row is more than 16,382; is parameter error *)
  3900.             error := paramErr;
  3901.       END
  3902.    ELSE
  3903.       (* Pixel depth isn’t valid; is parameter error *)
  3904.       error := paramErr;
  3905.    (* If sanity checks succeed, then allocate a new CGrafPort *)
  3906.    IF error = noErr THEN
  3907.       BEGIN
  3908.          newPort := CGrafPtr(NewPtr(SizeOf (CGrafPort)));
  3909.          IF newPort <> NIL THEN
  3910.             BEGIN
  3911.                (* Save the current port *)
  3912.                GetPort(savedPort);
  3913.                (* Initialize the new CGrafPort and make it the current port *)
  3914.                OpenCPort(newPort);
  3915.                (* Set portRect, visRgn, and clipRgn to the given bounds rect *)
  3916.                newPort^.portRect := bounds;
  3917.                RectRgn(newPort^.visRgn, bounds);
  3918.                ClipRect(bounds);
  3919.                (* Initialize the new PixMap for off-screen drawing *)
  3920.                error := SetUpPixMap(depth, bounds, colors, bytesPerRow,
  3921.                      newPort^.portPixMap);
  3922.                IF error = noErr THEN
  3923.                   BEGIN
  3924.                      (* Grab the initialized PixMap handle *)
  3925.                      newPixMap := newPort^.portPixMap;
  3926.                      (* Allocate and initialize a new GDevice *)
  3927.                      error := CreateGDevice(newPixMap, newDevice);
  3928.                   END;
  3929.                (* Restore the saved port *)
  3930.                SetPort(savedPort);
  3931.             END
  3932.          ELSE
  3933.             error := MemError;
  3934.       END;
  3935.    (* Restore the given state of the color table *)
  3936.    IF colors <> NIL THEN
  3937.       HSetState(Handle(colors), savedState);
  3938.    (* One Last Look Around The House Before We Go… *)
  3939.    IF error <> noErr THEN
  3940.       BEGIN
  3941.          (* Some error occurred; dispose of everything we allocated *)
  3942.          IF newPixMap <> NIL THEN
  3943.             BEGIN
  3944.                DisposCTable(newPixMap^^.pmTable);
  3945.                DisposPtr(newPixMap^^.baseAddr);
  3946.             END;
  3947.          IF newDevice <> NIL THEN
  3948.             BEGIN
  3949.                DisposHandle(Handle(newDevice^^.gdITable));
  3950.                DisposHandle(Handle(newDevice));
  3951.             END;
  3952.          IF newPort <> NIL THEN
  3953.             BEGIN
  3954.                CloseCPort(newPort);
  3955.                DisposPtr(Ptr(newPort));
  3956.             END;
  3957.       END
  3958.    ELSE
  3959.       BEGIN
  3960.          (* Everything’s OK; return refs to off-screen CGrafPort and GDevice *)
  3961.          retPort := newPort;
  3962.          retGDevice := newDevice;
  3963.       END;
  3964.    CreateOffScreen := error;
  3965. END;
  3966. MPW C Listing 1
  3967. #define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */
  3968. OSErr CreateOffScreen(
  3969.     Rect       *bounds,     /* Bounding rectangle of off-screen */
  3970.     short      depth,       /* Desired number of bits per pixel in off-screen */
  3971.     CTabHandle colors,      /* Color table to assign to off-screen */
  3972.     CGrafPtr   *retPort,    /* Returns a pointer to the new CGrafPort */
  3973.     GDHandle   *retGDevice) /* Returns a handle to the new GDevice */
  3974. {
  3975.     CGrafPtr     newPort;     /* Pointer to the new off-screen CGrafPort */
  3976.     PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */
  3977.     GDHandle     newDevice;   /* Handle to the new off-screen GDevice */
  3978.     long         qdVersion;   /* Version of QuickDraw currently in use */
  3979.     GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */
  3980.     SignedByte   savedState;  /* Saved state of color table handle */
  3981.     short        bytesPerRow; /* Number of bytes per row in the PixMap */
  3982.     OSErr        error;       /* Returns error code */
  3983.     /* Initialize a few things before we begin */
  3984.     newPort = nil;
  3985.     newPixMap = nil;
  3986.     newDevice = nil;
  3987.     error = noErr;
  3988.     /* Save the color table’s current state and make sure it isn’t purgeable */
  3989.     if (colors != nil)
  3990.     {
  3991.         savedState = HGetState( (Handle)colors );
  3992.         HNoPurge( (Handle)colors );
  3993.     }
  3994.     /* Calculate the number of bytes per row in the off-screen PixMap */
  3995.     bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) >> 5) << 2;
  3996.     /* Get the current QuickDraw version */
  3997.     (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );
  3998.     /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */
  3999.     if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  4000.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  4001.     {
  4002.         /* Maximum number of bytes per row is 16,382; make sure within range */
  4003.         if (bytesPerRow <= kMaxRowBytes)
  4004.         {
  4005.             /* Make sure a color table is provided if the depth is indexed */
  4006.             if (depth <= 8)
  4007.                 if (colors == nil)
  4008.                   /* Indexed depth and clut is NIL; is parameter error */
  4009.                   error = paramErr;
  4010.         }
  4011.         else
  4012.             /* # of bytes per row is more than 16,382; is parameter error */
  4013.             error = paramErr;
  4014.     }
  4015.     else
  4016.         /* Pixel depth isn’t valid; is parameter error */
  4017.         error = paramErr;
  4018.     /* If sanity checks succeed, then allocate a new CGrafPort */
  4019.     if (error == noErr)
  4020.     {
  4021.         newPort = (CGrafPtr)NewPtr( sizeof (CGrafPort) );
  4022.         if (newPort != nil)
  4023.         {
  4024.             /* Save the current port */
  4025.             GetPort( &savedPort );
  4026.             /* Initialize the new CGrafPort and make it the current port */
  4027.             OpenCPort( newPort );
  4028.             /* Set portRect, visRgn, and clipRgn to the given bounds rect */
  4029.             newPort->portRect = *bounds;
  4030.             RectRgn( newPort->visRgn, bounds );
  4031.             ClipRect( bounds );
  4032.             /* Initialize the new PixMap for off-screen drawing */
  4033.             error = SetUpPixMap( depth, bounds, colors, bytesPerRow,
  4034.                     newPort->portPixMap );
  4035.             if (error == noErr)
  4036.             {
  4037.                 /* Grab the initialized PixMap handle */
  4038.                 newPixMap = newPort->portPixMap;
  4039.                 /* Allocate and initialize a new GDevice */
  4040.                 error = CreateGDevice( newPixMap, &newDevice );
  4041.             }
  4042.             /* Restore the saved port */
  4043.             SetPort( savedPort );
  4044.         }
  4045.         else
  4046.             error = MemError();
  4047.     }
  4048.     /* Restore the given state of the color table */
  4049.     if (colors != nil)
  4050.         HSetState( (Handle)colors, savedState );
  4051.     /* One Last Look Around The House Before We Go… */
  4052.     if (error != noErr)
  4053.     {
  4054.         /* Some error occurred; dispose of everything we allocated */
  4055.         if (newPixMap != nil)
  4056.         {
  4057.             DisposCTable( (**newPixMap).pmTable );
  4058.             DisposPtr( (**newPixMap).baseAddr );
  4059.         }
  4060.         if (newDevice != nil)
  4061.         {
  4062.             DisposHandle( (Handle)(**newDevice).gdITable );
  4063.             DisposHandle( (Handle)newDevice );
  4064.         }
  4065.         if (newPort != nil)
  4066.         {
  4067.             CloseCPort( newPort );
  4068.             DisposPtr( (Ptr)newPort );
  4069.         }
  4070.     }
  4071.     else
  4072.     {
  4073.         /* Everything’s OK; return refs to off-screen CGrafPort and GDevice */
  4074.         *retPort = newPort;
  4075.         *retGDevice = newDevice;
  4076.     }
  4077.     return error;
  4078. }
  4079. CreateOffScreen begins by making sure that the color table, if there is one, doesn’t get purged during the time that the off-screen graphics environment is created. Then, a sanity check is done for the given depth, bounds, and color table. The depth must be either 1, 2, 4, or 8 bits per pixel, or additionally 16 or 32 bits per pixel if 32-Bit QuickDraw is available. If these conditions aren’t satisfied, then it’s decided that there’s an error in the parameter list, and CreateOffScreen does nothing more. To determine whether 32-Bit QuickDraw is available or not, the _Gestalt routine is used. If _Gestalt returns a value that’s equal to or greater than the constant gestalt32BitQD, then 32-Bit QuickDraw is available and depths of 16 and 32 bits per pixel are supported. It’s not necessary to determine whether _Gestalt is available or not because it’s implemented as glue code in the Macintosh Programmer’s Workshop.
  4080. A check is then done to determine whether the number of bytes in each row of the off-screen pixel image is too much for QuickDraw to handle. Color QuickDraw can handle up to and including 16,382 ($3FFE) bytes in each row of any pixel image. If the required number of bytes per row exceeds this amount, then CreateOffScreen decides that there’s an error in the parameter list and does nothing more. The minimum number of bytes in a row that’s enough to cover the given boundary rectangle at the given pixel depth is calculated with the formula:
  4081.   bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  4082. This formula multiplies the number of pixels across the PixMap by the pixel depth to get the number of bits, and then this is divided by eight to get the number of bytes. This division by eight looks very strange because the number of bytes per row must be even, so this formula takes advantage of integer division and multiplication to make the result come out even. This particular formula additionally makes sure that the number of bytes per row is a multiple of four. This helps optimize the performance of Color QuickDraw operations because it allows Color QuickDraw to refer to each row beginning on a long word boundary in memory.
  4083. The last sanity check is to make sure that a color table is given as a parameter if it’s needed. Indexed-color graphics environments need color tables, so if the given pixel depth is eight or less (which implies an indexed-color graphics environment) and the given color table is NIL, then CreateOffScreen decides that there’s an error in the parameter list and does nothing more. If the given pixel depth is 16 or 32 (which implies a direct-color graphics environment), then CreateOffScreen ignores the given color table.
  4084. If all the sanity checks succeed, then the off-screen CGrafPort is allocated using a call to _NewPtr, and then it’s initialized and opened as a CGrafPort by passing the resulting pointer to _OpenCPort. Because _OpenCPort makes the new CGrafPort the current port, the current port is first saved so that it can be restored as the current port when CreateOffScreen is done.
  4085. As mentioned above, the _OpenCPort doesn’t necessarily initialize the portRect, visRgn, and clipRgn of the new CGrafPort to the areas that are needed for any particular off-screen graphics environment. So, the given boundary rectangle is assigned to the portRect field, _RectRgn is called to make the visRgn equal to the given boundary rectangle, and _ClipRect is called to set the clipRgn so that it’s equal to the given boundary rectangle.
  4086. The PixMap in the portPixMap field needs to be initialized for off-screen drawing, and that’s handled by the SetUpPixMap routine that’s described and defined in “Building the PixMap” later in this Note. Similarly, the off-screen GDevice must be created and initialized. That’s handled by the CreateGDevice routine that’s described and defined in “Building the GDevice” later in this Note.
  4087. Once these things are done, CreateOffScreen returns a pointer to the off-screen CGrafPort in the retPort parameter and a handle to the off-screen GDevice in the retGDevice parameter. The way to use these references is described in “Playing With Blocks”  later in this Note.
  4088. Building the PixMap
  4089. _OpenCPort initializes the portPixMap field of the CGrafPort it’s initializing with a copy of the PixMap of the current GDevice. When the CreateOffScreen routine described earlier executes, the current GDevice is unknown. So, all the fields of the PixMap that the new CGrafPort receives must be initialized so that it can be used for drawing off screen.* What follows is an overview of each of the PixMap fields and how they should be initialized for off-screen drawing.
  4090. baseAddr    pointer to the off-screen pixel image. The off-screen pixel image is allocated as a nonrelocatable block in the heap. The size of this block of memory is calculated from the rowBytes field, described next, multiplied by the number of rows in the given boundary rectangle.
  4091. rowBytes    number of bytes in each row of the pixel image. This value is calculated from the formula that’s given in the CreateOffScreen routine. The most significant bit of this field should be set so that Color QuickDraw knows that this is a PixMap rather than a BitMap. The maximum value, ignoring the most significant bit, is 16,382.
  4092. bounds    defines the coordinate system and the dimensions of the pixel image. For most off-screen drawing, this should be a rectangle that covers the entire off-screen graphics environment.
  4093. pmVersion    set of internally and externally defined flags. As of 32-Bit QuickDraw 1.2, only the baseAddr32 flag is defined externally. This flag is described in “Choosing Your Off-Screen Memory” later in this Note. For most off-screen drawing, this field is set to zero.
  4094. *This part of these routines really bothers me because it feels impure to initialize all the PixMap fields when _OpenCPort has initialized them already, just not in a way that’s any good for off-screen drawing. I tried creating the GDevice and PixMap first and then calling _OpenCPort so that it initializes its PixMap for off-screen drawing, but then you end up with two pixel maps and that makes this tougher to explain, or you have to dispose of one PixMap which seems worse than the method I’m using. 
  4095. packType    image compression scheme for pictures. The options for this field are discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 17-22 through 17-23. In this Note, image compression isn’t discussed so this field is set to zero.
  4096. packSize    internally used field. This field is always set to zero.
  4097. hRes    horizontal resolution of the pixel map. By default, the QuickDraw resolution is 72 dots per inch,which is the value this Note uses. This is a fixed-point field, so the actual value in this field is $00480000.
  4098. vRes    vertical resolution of the pixel map. See the hRes description.
  4099. pixelType    format of the pixels. In indexed-color pixel maps, this field holds zero. In direct-color pixel maps, this field holds the RGBDirect constant, which is equal to 16.
  4100. pixelSize    number of bits in every pixel. For indexed-color pixels, this is 1, 2, 4, or 8 bits per pixel. For direct-color pixels, this is 16 or 32 bits per pixel.
  4101. cmpCount    number of components in every pixel. In indexed-color pixel maps, this field is set to 1. In direct-color pixel maps, this field is set to 3. Sometimes it’s handy to set this field to 4 in 32-bit deep pixel maps when they’re being saved in a picture. See the “Color QuickDraw” chapter of Inside Macintosh Volume VI, page 17-23, for details about this.
  4102. cmpSize    number of bits in each color component. In indexed-color pixel maps, this field is set to the same value that’s in the pixelSize field. In 16-bit deep direct pixel maps, this field is set to 5. In 32-bit deep direct pixel maps, this field is set to 8.
  4103. planeBytes    not currently defined. This field is set to zero.
  4104. pmTable    handle to the color table for indexed-color pixel maps. A method to create a color table is given in “About That Creation Thing . . .” later in this Note. In direct-color pixel maps, this field contains a handle to a dummy color table, and building one of these is shown in the SetUpPixMap routine in Listing 2.
  4105. pmReserved    not currently defined. This field is set to zero.
  4106. The SetUpPixMap routine in Listing 2 initializes the PixMap that’s passed to it in the aPixMap parameter so that it can be used in an off-screen graphics environment. The depth, bounds, and color parameters are the same as the ones passed to the CreateOffScreen routine. The bytesPerRow parameter is the number of bytes in each row of the off-screen pixel image. A description of SetUpPixMap follows the listing.
  4107. MPW Pascal Listing 2
  4108. FUNCTION SetUpPixMap(
  4109.    depth:       Integer;     {Desired number of bits/pixel in off-screen}
  4110.    bound:       Rect;        {Bounding rectangle of off-screen}
  4111.    colors:      CTabHandle;  {Color table to assign to off-screen}
  4112.    bytesPerRow: Integer;     {Number of bytes in each row of pixels}
  4113.    aPixMap:     PixMapHandle {Handle to the PixMap being initialized}
  4114.    ): OSErr;
  4115.    CONST
  4116.       kDefaultRes = $00480000; {Default resolution is 72 DPI; Fixed type}
  4117.    VAR
  4118.       newColors:   CTabHandle; {Color table used for the off-screen PixMap}
  4119.       offBaseAddr: Ptr;        {Pointer to the off-screen pixel image}
  4120.       error:       OSErr;      {Returns error code}
  4121. BEGIN
  4122.    error := noErr;
  4123.    newColors := NIL;
  4124.     offBaseAddr := NIL;
  4125.    (* Clone the clut if indexed color; allocate a dummy clut if direct color *)
  4126.    IF depth <= 8 THEN
  4127.       BEGIN
  4128.          newColors := colors;
  4129.          error := HandToHand(Handle(newColors));
  4130.       END
  4131.    ELSE
  4132.       BEGIN
  4133.          newColors := CTabHandle(NewHandle(SizeOf(ColorTable) -
  4134.                SizeOf(CSpecArray)));
  4135.          error := MemError;
  4136.       END;
  4137.    IF error = noErr THEN
  4138.       BEGIN
  4139.          (* Allocate pixel image; long integer multiplication avoids overflow *)
  4140.          offBaseAddr := NewPtr(LongInt(bytesPerRow) * (bound.bottom -
  4141.                bound.top));
  4142.          IF offBaseAddr <> NIL THEN
  4143.             WITH aPixMap^^ DO
  4144.                BEGIN
  4145.                   (* Initialize fields common to indexed and direct PixMaps *)
  4146.                   baseAddr := offBaseAddr;     {Point to image}
  4147.                   rowBytes := BOR(bytesPerRow, {MSB set for PixMap}
  4148.                         $8000);
  4149.                   bounds := bound;             {Use given bounds}
  4150.                   pmVersion := 0;              {No special stuff}
  4151.                   packType := 0;               {Default PICT pack}
  4152.                   packSize := 0;               {Always zero when in memory}
  4153.                   hRes := kDefaultRes;         {72 DPI default resolution}
  4154.                   vRes := kDefaultRes;         {72 DPI default resolution}
  4155.                   pixelSize := depth;          {Set number of bits/pixel}
  4156.                   planeBytes := 0;             {Not used}
  4157.                   pmReserved := 0;             {Not used}
  4158.                   (* Initialize fields specific to indexed and direct PixMaps *)
  4159.                   IF depth <= 8 THEN
  4160.                      BEGIN
  4161.                         (* PixMap is indexed *)
  4162.                         pixelType := 0;       {Indicates indexed}
  4163.                         cmpCount := 1;        {Have 1 component}
  4164.                         cmpSize := depth;     {Component size=depth}
  4165.                         pmTable := newColors; {Handle to CLUT}
  4166.                      END
  4167.                   ELSE
  4168.                      BEGIN
  4169.                         (* PixMap is direct *)
  4170.                         pixelType := RGBDirect; {Indicates direct}
  4171.                         cmpCount := 3;          {Have 3 components}
  4172.                         IF depth = 16 THEN
  4173.                            cmpSize := 5         {5 bits/component}
  4174.                         ELSE
  4175.                            cmpSize := 8;        {8 bits/component}
  4176.                         (* Initialize fields of the dummy color table *)
  4177.                         newColors^^.ctSeed := 3 * aPixMap^^.cmpSize;
  4178.                         newColors^^.ctFlags := 0;
  4179.                         newColors^^.ctSize := 0;
  4180.                         pmTable := newColors;
  4181.                      END;
  4182.                END
  4183.          ELSE
  4184.             error := MemError;
  4185.       END
  4186.    ELSE
  4187.       newColors := NIL;
  4188.    (* If no errors occurred, return a handle to the new off-screen PixMap *)
  4189.    IF error <> noErr THEN
  4190.       BEGIN
  4191.          IF newColors <> NIL THEN
  4192.             DisposCTable(newColors);
  4193.       END;
  4194.     (* Return the error code *)
  4195.     SetUpPixMap := error;
  4196. END;
  4197. MPW C Listing 2
  4198. #define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
  4199. OSErr SetUpPixMap(
  4200.     short        depth,       /* Desired number of bits/pixel in off-screen */
  4201.     Rect         *bounds,     /* Bounding rectangle of off-screen */
  4202.     CTabHandle   colors,      /* Color table to assign to off-screen */
  4203.     short        bytesPerRow, /* Number of bytes per row in the PixMap */
  4204.     PixMapHandle aPixMap)     /* Handle to the PixMap being initialized */
  4205. {
  4206.     CTabHandle newColors;   /* Color table used for the off-screen PixMap */
  4207.     Ptr        offBaseAddr; /* Pointer to the off-screen pixel image */
  4208.     OSErr      error;       /* Returns error code */
  4209.     error = noErr;
  4210.     newColors = nil;
  4211.     offBaseAddr = nil;
  4212.     /* Clone the clut if indexed color; allocate a dummy clut if direct color */
  4213.     if (depth <= 8)
  4214.     {
  4215.         newColors = colors;
  4216.         error = HandToHand( (Handle *)&newColors );
  4217.     }
  4218.     else
  4219.     {
  4220.         newColors = (CTabHandle)NewHandle( sizeof (ColorTable) -
  4221.                 sizeof (CSpecArray) );
  4222.         error = MemError();
  4223.     }
  4224.     if (error == noErr)
  4225.     {
  4226.         /* Allocate pixel image; long integer multiplication avoids overflow */
  4227.         offBaseAddr = NewPtr( (unsigned long)bytesPerRow * (bounds->bottom -
  4228.                 bounds->top) );
  4229.         if (offBaseAddr != nil)
  4230.         {
  4231.             /* Initialize fields common to indexed and direct PixMaps */
  4232.             (**aPixMap).baseAddr = offBaseAddr;  /* Point to image */
  4233.             (**aPixMap).rowBytes = bytesPerRow | /* MSB set for PixMap */
  4234.                     0x8000;
  4235.             (**aPixMap).bounds = *bounds;        /* Use given bounds */
  4236.             (**aPixMap).pmVersion = 0;           /* No special stuff */
  4237.             (**aPixMap).packType = 0;            /* Default PICT pack */
  4238.             (**aPixMap).packSize = 0;            /* Always zero in mem */
  4239.             (**aPixMap).hRes = kDefaultRes;      /* 72 DPI default res */
  4240.             (**aPixMap).vRes = kDefaultRes;      /* 72 DPI default res */
  4241.             (**aPixMap).pixelSize = depth;       /* Set # bits/pixel */
  4242.             (**aPixMap).planeBytes = 0;          /* Not used */
  4243.             (**aPixMap).pmReserved = 0;          /* Not used */
  4244.             /* Initialize fields specific to indexed and direct PixMaps */
  4245.             if (depth <= 8)
  4246.             {
  4247.                 /* PixMap is indexed */
  4248.                 (**aPixMap).pixelType = 0;       /* Indicates indexed */
  4249.                 (**aPixMap).cmpCount = 1;        /* Have 1 component */
  4250.                 (**aPixMap).cmpSize = depth;     /* Component size=depth */
  4251.                 (**aPixMap).pmTable = newColors; /* Handle to CLUT */
  4252.             }
  4253.             else
  4254.             {
  4255.                 /* PixMap is direct */
  4256.                 (**aPixMap).pixelType = RGBDirect; /* Indicates direct */
  4257.                 (**aPixMap).cmpCount = 3;          /* Have 3 components */
  4258.                 if (depth == 16)
  4259.                     (**aPixMap).cmpSize = 5;       /* 5 bits/component */
  4260.                 else
  4261.                     (**aPixMap).cmpSize = 8;       /* 8 bits/component */
  4262.                 (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;
  4263.                 (**newColors).ctFlags = 0;
  4264.                 (**newColors).ctSize = 0;
  4265.                 (**aPixMap).pmTable = newColors;
  4266.             }
  4267.         }
  4268.         else
  4269.             error = MemError();
  4270.     }
  4271.     else
  4272.         newColors = nil;
  4273.     /* If no errors occurred, return a handle to the new off-screen PixMap */
  4274.     if (error != noErr)
  4275.     {
  4276.         if (newColors != nil)
  4277.             DisposCTable( newColors );
  4278.     }
  4279.     /* Return the error code */
  4280.     return error;
  4281. }
  4282. SetUpPixMap begins by copying the given color table if an indexed-color graphics environment is being built, or allocating a dummy color table if a direct-color graphics environment is being built. A copy of the color table is made because this allows the given color table and the off-screen graphics environment’s color table to be manipulated independently without interfering with each other, and this lets the off-screen graphics environment routines manipulate the color table without needing to worry about whether the color table is a 'clut' resource or not. The dummy color table is made so that routines which assume that every PixMap has a color table won’t do something catastrophic if they find a NIL color table. The off-screen pixel image is then allocated as a nonrelocatable block in the application’s heap.
  4283. Some of the fields of a PixMap have to be initialized differently depending upon whether the indexed-color model or the direct-color model is being used. So, the fields that are the same regardless of the color model that’s being used are assigned first. Then the desired pixel depth is compared to 8. If the depth is less than or equal to 8, then the rest of the fields are initialized for the indexed-color model. Otherwise, the rest of the fields are initialized for the direct color model. In the case of the direct-color model, the dummy color table is initialized to have no CSpecArray entries and its ctSeed field is set to three times the component size. This dummy color table is then installed into the PixMap.
  4284. Once SetUpPixMap completes, the PixMap of the new CGrafPort is ready to hold an off-screen image. It’s not quite ready to be drawn into with Color QuickDraw though. To do that, the off-screen GDevice is still needed; the construction and initialization of the GDevice are covered in the next section.
  4285. Building the GDevice
  4286. The _OpenCPort routine automatically allocates and initializes a PixMap, and the SetUpPixMap routine reinitializes that existing PixMap. _OpenCPort doesn’t allocate nor initialize a GDevice, so one has to be created from scratch. Pages 21-20 through 21-21 of “The Graphics Devices Manager” chapter of Inside Macintosh Volume VI describe the _NewGDevice routine. This routine seems as though it’s the ticket to getting a GDevice for off-screen drawing, but it always allocates the new GDevice in the system heap. That’s not so good because if your program unexpectedly quits or if you just forget to dispose of the GDevice before you quit for real, the GDevice gets orphaned in the system heap. To prevent this from happening, _NewGDevice should be ignored and the off-screen GDevice should instead be allocated and initialized from scratch. What follows is a description of how each field of the GDevice structure should be initialized.
  4287. gdRefNum    reference number of video driver. Off-screen graphics environments don’t need to have video drivers because there’s no video device associated with them, so this field is set to zero.
  4288. gdID    used to identify specific GDevice structures from color-search procedures. This isn’t necessary for off-screen drawing, so this is normally set to zero.
  4289. gdType    type of GDevice. This field is set to the constant clutType (equal to zero) for an indexed-color environment and set to the constant directType (equal to 2) for a direct-color environment.
  4290. gdITable    handle to the inverse table. Initially, this field is set to an arbitrarily small handle. Later, the _MakeITable routine is used to resize and initialize this handle to a real inverse table.
  4291. gdResPref    inverse-table resolution. When _MakeITable is called by QuickDraw, the value of this field is used as the inverse-table resolution. Almost all inverse tables have a resolution of 4. There are some cases when a inverse-table resolution of 5 is useful, particularly when the arithmetic transfer modes are used with _CopyBits. See “The GDevice” earlier in this Note.
  4292. gdSearchProc    pointer to the color-search procedure. If a color-search procedure is needed, this field can be set later by calling the _AddSearch routine (see the “Color Manager” chapter of Inside Macintosh Volume V, pages 145 through 147). Usually, this field is just set to NIL and left at that.
  4293. gdCompProc    pointer to the color-complement procedure. If a color-complement procedure is needed, this field can be set later by calling the _AddComp routine (see the “Color Manager” chapter of Inside Macintosh Volume V, pages 145 through 147). Usually, this field is set to NIL and left at that.
  4294. gdFlags    flags indicating certain states of the GDevice. This field should initially be set to zeroes. After the GDevice has been built, these flags can be set with the _SetDeviceAttrs routine (see the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI, pages 21-10 and 21-22).
  4295. gdPMap    handle to a PixMap. A handle to the PixMap of the CGrafPort that was created earlier is put into this field.
  4296. gdRefCon    miscellaneous data. _CalcCMask and _SeedCFill use this field as described on pages 71 through 72 of Inside Macintosh Volume V. Initially, this field is set to zero.
  4297. gdNextGD    handle to next GDevice in the GDevice list. The system maintains a linked list of GDevice records in which there’s one GDevice for every screen, and the links are kept in this field. Off-screen GDevice structures should never be put into this list, so this field should be set to NIL.
  4298. gdRect    rectangle of GDevice. Strictly speaking, this field is used only for screens, but it should be the same as the bounds rectangle of the off-screen PixMap.
  4299. gdMode    current video mode. This field is used by video drivers to keep track of the current mode that the video device is in. For off-screen GDevice structures, this field should be set to -1.
  4300. gdCC…    These four fields are used only with GDevice structures for screens. For off-screen GDevice structures, these fields should be set to zero.
  4301. gdReserved    not currently defined. This field is set to zero.
  4302. The CreateGDevice routine shown below in Listing 3 allocates and initializes a GDevice structure. It takes the initialized off-screen PixMap in the basePixMap parameter and returns the initialized GDevice in the retGDevice parameter. If any error occurs, any memory that’s allocated is disposed of and the result code is returned as a function result.
  4303. MPW Pascal Listing 3
  4304. FUNCTION CreateGDevice(
  4305.    basePixMap:     PixMapHandle; {Handle to the PixMap to base GDevice on}
  4306.    VAR retGDevice: GDHandle      {Returns a handle to the new GDevice}
  4307.    ): OSErr;
  4308.    CONST
  4309.       kITabRes = 4; {Inverse-table resolution}
  4310.    VAR
  4311.       newDevice:  GDHandle;   {Handle to the new GDevice}
  4312.       embryoITab: ITabHandle; {Handle to the embryonic inverse table}
  4313.       error:      OSErr;      {Error code}
  4314. BEGIN
  4315.    (* Initialize a few things before we begin *)
  4316.    error := noErr;
  4317.    newDevice := NIL;
  4318.    embryoITab := NIL;
  4319.    (* Allocate memory for the new GDevice *)
  4320.    newDevice := GDHandle(NewHandle(SizeOf(GDevice)));
  4321.    IF newDevice <> NIL THEN
  4322.       BEGIN
  4323.          (* Allocate the embryonic inverse table *)
  4324.          embryoITab := ITabHandle(NewHandleClear(2));
  4325.          IF embryoITab <> NIL THEN
  4326.             BEGIN
  4327.                (* Initialize the new GDevice fields *)
  4328.                WITH newDevice^^ DO
  4329.                   BEGIN
  4330.                      gdRefNum := 0;                 {Only used for screens}
  4331.                      gdID := 0;                     {Won’t normally use}
  4332.                      IF basePixMap^^.pixelSize <= 8 THEN
  4333.                         gdType := clutType          {Depth≤8; clut device}
  4334.                      ELSE
  4335.                         gdType := directType;       {Depth>8; direct device}
  4336.                      gdITable := embryoITab;        {2-byte handle for now}
  4337.                      gdResPref := kITabRes;         {Normal inv table res}
  4338.                      gdSearchProc := NIL;           {No color-search proc}
  4339.                      gdCompProc := NIL;             {No complement proc}
  4340.                      gdFlags := 0;                  {Will set these later}
  4341.                      gdPMap := basePixMap;          {Reference our PixMap}
  4342.                      gdRefCon := 0;                 {Won’t normally use}
  4343.                      gdNextGD := NIL;               {Not in GDevice list}
  4344.                      gdRect := basePixMap^^.bounds; {Use PixMap dimensions}
  4345.                      gdMode := -1;                  {For nonscreens}
  4346.                      gdCCBytes := 0;                {Only used for screens}
  4347.                      gdCCDepth := 0;                {Only used for screens}
  4348.                      gdCCXData := NIL;              {Only used for screens}
  4349.                      gdCCXMask := NIL;              {Only used for screens}
  4350.                      gdReserved := 0;               {Currently unused}
  4351.                   END;
  4352.                (* Set color-device bit if PixMap isn’t black & white *)
  4353.                IF basePixMap^^.pixelSize > 1 THEN
  4354.                   SetDeviceAttribute(newDevice, gdDevType, true);
  4355.                (* Set bit to indicate that the GDevice has no video driver *)
  4356.                SetDeviceAttribute(newDevice, noDriver, true);
  4357.                (* Initialize the inverse table *)
  4358.                IF basePixMap^^.pixelSize <= 8 THEN
  4359.                   BEGIN
  4360.                      MakeITable(basePixMap^^.pmTable, newDevice^^.gdITable,
  4361.                            newDevice^^.gdResPref);
  4362.                      error := QDError;
  4363.                   END;
  4364.             END
  4365.          ELSE
  4366.             error := MemError;
  4367.       END
  4368.    ELSE
  4369.       error := MemError;
  4370.    (* Handle any errors along the way *)
  4371.    IF error <> noErr THEN
  4372.       BEGIN
  4373.          IF embryoITab <> NIL THEN
  4374.             DisposHandle(Handle(embryoITab));
  4375.          IF newDevice <> NIL THEN
  4376.             DisposHandle(Handle(newDevice));
  4377.       END
  4378.    ELSE
  4379.       retGDevice := newDevice;
  4380.    (* Return a handle to the new GDevice *)
  4381.    CreateGDevice := error;
  4382. END;
  4383. MPW C Listing 3
  4384. #define kITabRes 4 /* Inverse-table resolution */
  4385. OSErr CreateGDevice(
  4386.     PixMapHandle basePixMap,  /* Handle to the PixMap to base GDevice on */
  4387.     GDHandle     *retGDevice) /* Returns a handle to the new GDevice */
  4388. {
  4389.     GDHandle   newDevice;  /* Handle to the new GDevice */
  4390.     ITabHandle embryoITab; /* Handle to the embryonic inverse table */
  4391.     Rect       deviceRect; /* Rectangle of GDevice */
  4392.     OSErr      error;      /* Error code */
  4393.     /* Initialize a few things before we begin */
  4394.     error = noErr;
  4395.     newDevice = nil;
  4396.     embryoITab = nil;
  4397.     /* Allocate memory for the new GDevice */
  4398.     newDevice = (GDHandle)NewHandle( sizeof (GDevice) );
  4399.     if (newDevice != nil)
  4400.     {
  4401.         /* Allocate the embryonic inverse table */
  4402.         embryoITab = (ITabHandle)NewHandleClear( 2 );
  4403.         if (embryoITab != nil)
  4404.         {
  4405.             /* Set rectangle of device to PixMap bounds */
  4406.             deviceRect = (**basePixMap).bounds;
  4407.             /* Initialize the new GDevice fields */
  4408.             (**newDevice).gdRefNum = 0;            /* Only used for screens */
  4409.             (**newDevice).gdID = 0;                /* Won’t normally use */
  4410.             if ((**basePixMap).pixelSize <= 8)
  4411.                 (**newDevice).gdType = clutType;   /* Depth≤8; clut device */
  4412.             else
  4413.                 (**newDevice).gdType = directType; /* Depth>8; direct device */
  4414.             (**newDevice).gdITable = embryoITab;   /* 2-byte handle for now */
  4415.             (**newDevice).gdResPref = kITabRes;    /* Normal inv table res */
  4416.             (**newDevice).gdSearchProc = nil;      /* No color-search proc */
  4417.             (**newDevice).gdCompProc = nil;        /* No complement proc */
  4418.             (**newDevice).gdFlags = 0;             /* Will set these later */
  4419.             (**newDevice).gdPMap = basePixMap;     /* Reference our PixMap */
  4420.             (**newDevice).gdRefCon = 0;            /* Won’t normally use */
  4421.             (**newDevice).gdNextGD = nil;          /* Not in GDevice list */
  4422.             (**newDevice).gdRect = deviceRect;     /* Use PixMap dimensions */
  4423.             (**newDevice).gdMode = -1;             /* For nonscreens */
  4424.             (**newDevice).gdCCBytes = 0;           /* Only used for screens */
  4425.             (**newDevice).gdCCDepth = 0;           /* Only used for screens */
  4426.             (**newDevice).gdCCXData = 0;           /* Only used for screens */
  4427.             (**newDevice).gdCCXMask = 0;           /* Only used for screens */
  4428.             (**newDevice).gdReserved = 0;          /* Currently unused */
  4429.             /* Set color-device bit if PixMap isn’t black & white */
  4430.             if ((**basePixMap).pixelSize > 1)
  4431.                 SetDeviceAttribute( newDevice, gdDevType, true );
  4432.             /* Set bit to indicate that the GDevice has no video driver */
  4433.             SetDeviceAttribute( newDevice, noDriver, true );
  4434.             /* Initialize the inverse table */
  4435.             if ((**basePixMap).pixelSize <= 8)
  4436.             {
  4437.                 MakeITable( (**basePixMap).pmTable, (**newDevice).gdITable,
  4438.                         (**newDevice).gdResPref );
  4439.                 error = QDError();
  4440.             }
  4441.         }
  4442.         else
  4443.             error = MemError();
  4444.     }
  4445.     else
  4446.         error = MemError();
  4447.     /* Handle any errors along the way */
  4448.     if (error != noErr)
  4449.     {
  4450.         if (embryoITab != nil)
  4451.             DisposHandle( (Handle)embryoITab );
  4452.         if (newDevice != nil)
  4453.             DisposHandle( (Handle)newDevice );
  4454.     }
  4455.     else
  4456.         *retGDevice = newDevice;
  4457.     /* Return a handle to the new GDevice */
  4458.     return error;
  4459. }
  4460. CreateGDevice begins by allocating the GDevice structure and an embryonic form of the inverse table in the current heap. The inverse table is allocated as two zero bytes for now; it’ll be resized and initialized to be a real inverse table later in this routine. Then, each of the GDevice fields are initialized as described earlier.
  4461. After all the fields have been initialized, the gdFlags field is set through _SetDeviceAttribute. If the desired pixel depth is greater than 1, then the gdDevType bit is set. This indicates that the GDevice is for a color graphics environment. This bit should be set even if a gray-scale color table is used for this off-screen graphics environment. The noDriver bit is set because this is an off-screen GDevice and so there’s no associated video device driver.
  4462. Finally, the inverse table is resized and initialized by calling the _MakeITable routine. A handle to the two-byte embryonic inverse table that was created earlier in CreateGDevice is passed as a parameter, as is a handle to the off-screen color table and the preferred inverse-table resolution.
  4463. All Fall Down
  4464. Now that we have a way to create an off-screen graphics environment, there has to be a way to get rid of it too. The DisposeOffScreen routine shown in Listing 4 does this. The CreateOffScreen routine returns an off-screen graphics environment that’s represented by a CGrafPort and GDevice. The DisposeOffScreen routine takes the off-screen CGrafPort and GDevice and deallocates all the memory that’s associated with them including the CGrafPort and its dependent structures, the GDevice, the PixMap, the color table, and the inverse table.
  4465. MPW Pascal Listing 4
  4466. PROCEDURE DisposeOffScreen(
  4467.    doomedPort:    CGrafPtr; {Pointer to the CGrafPort we’re getting rid of}
  4468.    doomedGDevice: GDHandle  {Handle to the GDevice we’re getting rid of}
  4469.    );
  4470.    VAR
  4471.       currPort:    CGrafPtr; {Pointer to the current port}
  4472.       currGDevice: GDHandle; {Handle to the current GDevice}
  4473. BEGIN
  4474.    (* Check to see whether the doomed CGrafPort is the current port *)
  4475.    GetPort(GrafPtr(currPort));
  4476.    IF currPort = doomedPort THEN
  4477.       BEGIN
  4478.          (* It is; set current port to Window Manager CGrafPort *)
  4479.          GetCWMgrPort(currPort);
  4480.          SetPort(GrafPtr(currPort));
  4481.       END;
  4482.    (* Check to see whether the doomed GDevice is the current GDevice *)
  4483.    currGDevice := GetGDevice;
  4484.    IF currGDevice = doomedGDevice THEN
  4485.       (* It is; set current GDevice to the main screen’s GDevice *)
  4486.       SetGDevice(GetMainDevice);
  4487.    (* Throw everything away *)
  4488.    doomedGDevice^^.gdPMap := NIL;
  4489.    DisposGDevice(doomedGDevice);
  4490.    DisposPtr(doomedPort^.portPixMap^^.baseAddr);
  4491.    IF doomedPort^.portPixMap^^.pmTable <> NIL THEN
  4492.       DisposCTable(doomedPort^.portPixMap^^.pmTable);
  4493.    CloseCPort(doomedPort);
  4494.    DisposPtr(Ptr(doomedPort));
  4495. END;
  4496. MPW C Listing 4
  4497. void DisposeOffScreen(
  4498.     CGrafPtr doomedPort,    /* Pointer to the CGrafPort to be disposed of */
  4499.     GDHandle doomedGDevice) /* Handle to the GDevice to be disposed of */
  4500. {
  4501.     CGrafPtr currPort;    /* Pointer to the current port */
  4502.     GDHandle currGDevice; /* Handle to the current GDevice */
  4503.     /* Check to see whether the doomed CGrafPort is the current port */
  4504.     GetPort( (GrafPtr *)&currPort );
  4505.     if (currPort == doomedPort)
  4506.     {
  4507.         /* It is; set current port to Window Manager CGrafPort */
  4508.         GetCWMgrPort( &currPort );
  4509.         SetPort( (GrafPtr)currPort );
  4510.     }
  4511.     /* Check to see whether the doomed GDevice is the current GDevice */
  4512.     currGDevice = GetGDevice();
  4513.     if (currGDevice == doomedGDevice)
  4514.         /* It is; set current GDevice to the main screen’s GDevice */
  4515.         SetGDevice( GetMainDevice() );
  4516.     /* Throw everything away */
  4517.     (**doomedGDevice).gdPMap = nil;
  4518.     DisposGDevice( doomedGDevice );
  4519.     DisposPtr( (**doomedPort->portPixMap).baseAddr );
  4520.     if ((**doomedPort->portPixMap).pmTable != nil)
  4521.         DisposCTable( (**doomedPort->portPixMap).pmTable );
  4522.     CloseCPort( doomedPort );
  4523.     DisposPtr( (Ptr)doomedPort );
  4524. }
  4525. One mildly tricky aspect of this is that we shouldn’t dispose of the current graphics environment. To prevent this, the current port is retrieved by a call to _GetPort. If it returns a pointer to the same port that DisposeOffScreen is disposing, then the current port is set to the Window Manager’s CGrafPort. That was an arbitrary choice, but it’s the most neutral. Similarly, the current GDevice is retrieved by a call to _GetGDevice. If it returns a handle to the same GDevice that DisposeOffScreen is disposing, then the current port is set to the main screen’s GDevice. Again, that’s an arbitrary, neutral choice.
  4526. The inverse table, GDevice, pixel image, and color table are disposed of. Before disposing of the color table, a check is first made to see whether it’s NIL. That’s because it’s reasonable, though not normal, for the PixMap not to have even a dummy color table if the direct-color model is being used. Then the CGrafPort is closed which deallocates all the pieces associated with the CGrafPort, including the PixMap. Once this is done, all the structures that were created by calling CreateOffScreen are deallocated.
  4527. Playing With Blocks
  4528. Now that these four routines with two entry points can create and dispose of off-screen graphics environments, how are they used? There are several phases to using an off-screen graphics environment: creating it, drawing into it, switching between it and other off-screen and on-screen graphics environments, copying images to and from it, and disposing of it. Listing 5 shows a routine called ExerciseOffScreen which is a very basic example of all of these phases.
  4529. MPW Pascal Listing 5
  4530. PROCEDURE ExerciseOffScreen;
  4531.    CONST
  4532.       kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}
  4533.       rGrayClut  = 1600; {Resource ID of gray-scale clut}
  4534.       rColorClut = 1601; {Resource ID of full-color clut}
  4535.    VAR
  4536.       grayPort:    CGrafPtr;   {Graphics environment for gray off screen}
  4537.       grayDevice:  GDHandle;   {Color environment for gray off screen}
  4538.       colorPort:   CGrafPtr;   {Graphics environment for color off screen}
  4539.       colorDevice: GDHandle;   {Color environment for color off screen}
  4540.       savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  4541.       savedDevice: GDHandle;   {Handle to the saved color environment}
  4542.       offColors:   CTabHandle; {Colors for off-screen environments}
  4543.       offRect:     Rect;       {Rectangle of off-screen environments}
  4544.       circleRect:  Rect;       {Rectangles for circle-drawing}
  4545.       count:       Integer;    {Generic counter}
  4546.       aColor:      RGBColor;   {Color used for drawing off screen}
  4547.       error:       OSErr;      {Error return from off-screen creation}
  4548. BEGIN
  4549.    (* Set up the rectangle for the off-screen graphics environments *)
  4550.    SetRect(offRect, 0, 0, 256, 256);
  4551.    (* Get the color table for the gray off-screen graphics environment *)
  4552.    offColors := GetCTable(rGrayClut);
  4553.    (* Create the gray off-screen graphics environment *)
  4554.    error := CreateOffScreen(offRect, kOffDepth, offColors, grayPort,
  4555.          grayDevice);
  4556.    IF error = noErr THEN
  4557.       BEGIN
  4558.          (* Get the color table for the color off-screen graphics environment *)
  4559.          offColors := GetCTable(rColorClut);
  4560.          (* Create the color off-screen graphics environment *)
  4561.          error := CreateOffScreen(offRect, kOffDepth, offColors, colorPort,
  4562.                colorDevice);
  4563.          IF error = noErr THEN
  4564.             BEGIN
  4565.                (* Save the current graphics environment *)
  4566.                GetPort(savedPort);
  4567.                savedDevice := GetGDevice;
  4568.                (* Set the current graphics environment to the gray one *)
  4569.                SetPort(GrafPtr(grayPort));
  4570.                SetGDevice(grayDevice);
  4571.                (* Draw gray-scale ramp into the gray off-screen environment *)
  4572.                FOR count := 0 TO 255 DO
  4573.                   BEGIN
  4574.                      aColor.red := count * 257;
  4575.                      aColor.green := aColor.red;
  4576.                      aColor.blue := aColor.green;
  4577.                      RGBForeColor(aColor);
  4578.                      MoveTo(0, count);
  4579.                      LineTo(255, count);
  4580.                   END;
  4581.                (* Copy gray ramp into color off-screen colorized with green *)
  4582.                SetPort(GrafPtr(colorPort));
  4583.                SetGDevice(colorDevice);
  4584.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  4585.                RGBForeColor(aColor);
  4586.                CopyBits(GrafPtr(grayPort)^.portBits,
  4587.                      GrafPtr(colorPort)^.portBits,
  4588.                      grayPort^.portRect,
  4589.                      colorPort^.portRect,
  4590.                      srcCopy + ditherCopy, NIL);
  4591.                (* Draw red, green, and blue circles *)
  4592.                PenSize(8, 8);
  4593.                aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;
  4594.                RGBForeColor(aColor);
  4595.                circleRect := colorPort^.portRect;
  4596.                FrameOval(circleRect);
  4597.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  4598.                RGBForeColor(aColor);
  4599.                InsetRect(circleRect, 20, 20);
  4600.                FrameOval(circleRect);
  4601.                aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;
  4602.                RGBForeColor(aColor);
  4603.                InsetRect(circleRect, 20, 20);
  4604.                FrameOval(circleRect);
  4605.                (* Copy the color off-screen environment to the current port *)
  4606.                SetPort(savedPort);
  4607.                SetGDevice(savedDevice);
  4608.                CopyBits(GrafPtr(colorPort)^.portBits, savedPort^.portBits,
  4609.                      colorPort^.portRect, savedPort^.portRect,
  4610.                      srcCopy, NIL);
  4611.                (* Dispose of the off-screen graphics environments *)
  4612.                DisposeOffScreen(grayPort, grayDevice);
  4613.                DisposeOffScreen(colorPort, colorDevice);
  4614.             END;
  4615.       END;
  4616. END;
  4617. MPW C Listing 5
  4618. #define kOffDepth  8    /* Number of bits per pixel in off-screen environment */
  4619. #define rGrayClut  1600 /* Resource ID of gray-scale clut */
  4620. #define rColorClut 1601 /* Resource ID of full-color clut */
  4621. void ExerciseOffScreen()
  4622. {
  4623.     CGrafPtr   grayPort;    /* Graphics environment for gray off screen */
  4624.     GDHandle   grayDevice;  /* Color environment for gray off screen */
  4625.     CGrafPtr   colorPort;   /* Graphics environment for color off screen */
  4626.     GDHandle   colorDevice; /* Color environment for color off screen */
  4627.     GrafPtr    savedPort;   /* Pointer to the saved graphics environment */
  4628.     GDHandle   savedDevice; /* Handle to the saved color environment */
  4629.     CTabHandle offColors;   /* Colors for off-screen environments */
  4630.     Rect       offRect;     /* Rectangle of off-screen environments */
  4631.     Rect       circleRect;  /* Rectangles for circle-drawing */
  4632.     short      count;       /* Generic counter */
  4633.     RGBColor   aColor;      /* Color used for drawing off screen */
  4634.     OSErr      error;       /* Error return from off-screen creation */
  4635.     /* Set up the rectangle for the off-screen graphics environments */
  4636.     SetRect( &offRect, 0, 0, 256, 256 );
  4637.     /* Get the color table for the gray off-screen graphics environment */
  4638.     offColors = GetCTable( rGrayClut );
  4639.     /* Create the gray off-screen graphics environment */
  4640.     error = CreateOffScreen( &offRect, kOffDepth, offColors,
  4641.             &grayPort, &grayDevice );
  4642.     if (error == noErr)
  4643.     {
  4644.         /* Get the color table for the color off-screen graphics environment */
  4645.         offColors = GetCTable( rColorClut );
  4646.         /* Create the color off-screen graphics environment */
  4647.         error = CreateOffScreen( &offRect, kOffDepth, offColors,
  4648.                 &colorPort, &colorDevice );
  4649.         if (error == noErr)
  4650.         {
  4651.             /* Save the current graphics environment */
  4652.             GetPort( &savedPort );
  4653.             savedDevice = GetGDevice();
  4654.             /* Set the current graphics environment to the gray one */
  4655.             SetPort( (GrafPtr)grayPort );
  4656.             SetGDevice( grayDevice );
  4657.             /* Draw gray-scale ramp into the gray off-screen environment */
  4658.             for (count = 0; count < 256; ++count)
  4659.             {
  4660.                 aColor.red = aColor.green = aColor.blue = count * 257;
  4661.                 RGBForeColor( &aColor );
  4662.                 MoveTo( 0, count );
  4663.                 LineTo( 255, count );
  4664.             }
  4665.             /* Copy gray ramp into color off-screen colorized with green */
  4666.             SetPort( (GrafPtr)colorPort );
  4667.             SetGDevice( colorDevice );
  4668.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  4669.             RGBForeColor( &aColor );
  4670.             CopyBits( &((GrafPtr)grayPort)->portBits,
  4671.                     &((GrafPtr)colorPort)->portBits,
  4672.                     &grayPort->portRect,
  4673.                     &colorPort->portRect,
  4674.                     srcCopy | ditherCopy, nil );
  4675.             /* Draw red, green, and blue circles */
  4676.             PenSize( 8, 8 );
  4677.             aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;
  4678.             RGBForeColor( &aColor );
  4679.             circleRect = colorPort->portRect;
  4680.             FrameOval( &circleRect );
  4681.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  4682.             RGBForeColor( &aColor );
  4683.             InsetRect( &circleRect, 20, 20 );
  4684.             FrameOval( &circleRect );
  4685.             aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;
  4686.             RGBForeColor( &aColor );
  4687.             InsetRect( &circleRect, 20, 20 );
  4688.             FrameOval( &circleRect );
  4689.             /* Copy the color off-screen environment to the current port */
  4690.             SetPort( savedPort );
  4691.             SetGDevice( savedDevice );
  4692.             CopyBits( &((GrafPtr)colorPort)->portBits, &savedPort->portBits,
  4693.                     &colorPort->portRect, &savedPort->portRect,
  4694.                     srcCopy, nil );
  4695.             /* Dispose of the off-screen graphics environments */
  4696.             DisposeOffScreen( grayPort, grayDevice );
  4697.             DisposeOffScreen( colorPort, colorDevice );
  4698.         }
  4699.     }
  4700. }
  4701. Two off-screen graphics environments are created in the same way. A rectangle that’s 256 pixels wide by 256 pixels high and with its top-left coordinate at (0, 0) is created in the offRect local variable. 'clut' resources are loaded from the application’s resource fork to use as the color tables of the two off-screen graphics environments; a gray-scale 'clut' in the first case and a full-color 'clut' in the second case. Then, CreateOffScreen is called with the rectangle, color table, and a hard-coded pixel depth of eight bits per pixel.
  4702. If CreateOffScreen returns noErr in both cases, then the current graphics environment is saved so that it can be restored later. Graphics environments consist of the current port and the current GDevice. The current GrafPort or CGrafPort is saved with _GetPort. The current GDevice is saved with _GetGDevice.
  4703. The gray-scale off-screen graphics environment is set as the current graphics environment by calling _SetPort with its CGrafPort and calling _SetGDevice with its GDevice. A vertical gray ramp is drawn into this graphics environment with the usual set of QuickDraw calls. This graphics environment’s pixel image is then copied to the full-color off-screen graphics environment with dithering and colorization with green (dithering requires 32-Bit QuickDraw and consistent colorization requires system software version 7.0; both of these features are described in Konstantin Othmer’s article “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0” in Issue 6 of develop). Before this copy happens, the full-color off-screen graphics environment must be set as the current one. Once this is done, _CopyBits can properly map colors from the gray-scale off-screen graphics environment to the full-color one which gets a green ramp image.
  4704. Red, green, and blue concentric circles are drawn into the full-color off-screen graphics environment over the green ramp. This image is then copied to the graphics environment that was the current one when ExerciseOffScreen was called. To do this, the saved graphics environment is set as the current one by what should now be the familiar calls to _SetPort and _SetGDevice. The off-screen image is then copied to the saved graphics environment with _CopyBits.
  4705. Finally, the two off-screen graphics environments are disposed of by calling the DisposeOffScreen routine that’s defined in the section “All Fall Down”  earlier in this Note.
  4706. Put That Checkbook Away!
  4707. The previous section covered the basics of creating and using off-screen graphics environments. This is good enough for many, if not most, needs of off-screen drawing. But there are variations to creating and maintaining an off-screen graphics environment for specific cases. This section discusses a few of the more common cases.
  4708. About That Creation Thing . . .
  4709. The CreateOffScreen routine, defined in Listing 1, takes three pieces of information: the boundary rectangle, the desired pixel depth, and the desired color table. But there’s much more to these pieces than ExerciseOffScreen shows. This section describes these pieces in more detail.
  4710. The first parameter to CreateOffScreen is a rectangle which determines the size and coordinate system of the off-screen graphics environment. Usually, the top-left corner of the rectangle has the coordinate (0, 0) because it’s usually easiest to draw everything using coordinates that can also be thought of as the horizontal and vertical distance in pixels from the top-left corner of the graphics environment. But in some cases, it’s more convenient to have the (0, 0) coordinate somewhere else, and passing CreateOffScreen a rectangle with a nonzero coordinate in the top-left corner is an easy way to do this. The coordinate system can be translated after the off-screen graphics environment is created by using the _SetOrigin routine that’s described on pages 153 through 155 of Inside Macintosh Volume I.
  4711. Warning:    As Inside Macintosh Volume I, page 154, notes, the clip region of the port “sticks” to the coordinate system when you call _SetOrigin. If _SetOrigin offsets the coordinate system by a large amount, then the clip region might be moved completely outside of the port’s drawing area, and nothing can be drawn into that port. After calling _SetOrigin, you should set the clip region so that you can continue drawing into the port.
  4712. The number of bits per pixel implies the maximum number of available colors in a graphics environment, at least roughly speaking. The relationship between the number of bits per pixel and the number of available colors is discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-8 through 16-9.
  4713. If an indexed-color graphics environment is being made, then a color table must be passed to CreateOffScreen. In ExerciseOffScreen, the color table is retrieved from a 'clut' resource that’s in the application’s resource fork with a call to _GetCTable. Because CreateOffScreen clones this color table, this 'clut' resource can be purgeable so that it can be thrown out if its memory is needed for other purposes. _GetCTable can also be passed some special constants that tell it to allocate various system color tables that can also be passed to CreateOffScreen. These special constants are described on page 17-18 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI. _GetCTable allocates memory for these system color tables, so they should be disposed of after you’re done with them.
  4714. A color table could also be built from scratch by allocating it with a call to _NewHandle and then initializing it by hand. The ColorTable structure is documented on pages 48 through 49 of Inside Macintosh Volume V. Here’s what each of the fields should be set to:
  4715. ctSeed    identification value. This is an arbitrary value that should be changed any time the contents of the color table change so that the inverse table can be kept current. When Color QuickDraw draws anything, it compares the ctSeed of the color table of the PixMap of the current GDevice against the iTabSeed field of the inverse table of the current GDevice. If they’re the same, then Color QuickDraw uses colors according to that inverse table. If they’re different, then Color QuickDraw first rebuilds the inverse table according to the new color table’s contents and its iTabSeed is set to the value of the new color table’s ctSeed; then the rebuilt inverse table is used.
  4716.     When _CopyBits is called with the srcCopy transfer mode, the ctSeed fields of the source and destination pixel maps are compared. If they’re the same, then _CopyBits simply transfers the source pixels to the destination with no mapping of colors. If they’re different, then _CopyBits checks each entry of the color tables to determine whether they have the same colors for the same pixel values. If they do, then _CopyBits again simply transfers the source pixels to the destination with no mapping of colors. If they don’t, then _CopyBits maps colors in the source PixMap to the colors in the current graphics environment according to the inverse table of the current GDevice. The ctSeed field of a color table should be changed whenever its contents are changed so that _CopyBits doesn’t make the wrong assumptions about the equality of the source and destination color tables.
  4717.     You can get a seed value for a new color table by assigning to it the result of the _GetCTSeed routine, documented in the “Color Manager” chapter of Inside Macintosh Volume V, page 143. If the contents of an existing color table are changed, then it should be passed to the _CTabChanged routine which assigns a new value to its ctSeed field. If the _CTabChanged routine isn’t available (it’s available with 32-Bit QuickDraw and is included with the system beginning with system software version 7.0), then the ctSeed field should be given a new value with another call to _GetCTSeed.
  4718. ctFlags    indicates the Boolean characteristics of a color table. If the most significant bit of ctFlags is clear, then the value field of each ColorSpec entry in the ctTable array is interpreted as the pixel value for the color that’s specified in the rgb field in the same ColorSpec entry. You can build a color table with nonconsecutive pixel values this way. If this bit is set, then all the value fields in the color table are ignored and the index of each ColorSpec record in the ctTable array is that record’s pixel value. It’s your choice whether to clear this bit and set the value fields or set this bit and ignore the value fields; traditionally this bit is clear for off-screen color tables.
  4719.     If the next most significant bit of ctFlags is set, then the value field of each ColorSpec record in the ctTable array is used by _CopyBits as an index into the color palette that’s attached to the destination window, and the rgb field is ignored. This is documented in the “Palette Manager” chapter of Inside Macintosh Volume VI, page 20-17.
  4720.     The other bits are reserved for future use. If you create a color table from scratch, these other bits must be set to zero. If you use a color table that’s generated by the system, then these bits must be preserved.
  4721. ctSize    the number of color table entries minus 1. Normally, this field is set to 1, 3, 15, or 255 for 1-, 2-, 4-, and 8-bits per pixel, respectively. In special cases, it’s reasonable to have less than the maximum number of entries for the pixel depth. For example, a color table for an 8-bit per pixel graphics environment could have just 150 entries, in which case the ctSize field should hold 149. For this case, it’s still important to allocate as much space in the color table for the maximum number of entries for a pixel depth and clear the entries you’re not using to zero because some parts of Color QuickDraw assume the size of a color table based on the pixel depth.
  4722. ctTable    array of colors and pixel values. This table defines all the available colors in the color table and their pixel values. The value field of each ColorSpec record indicates that color’s pixel value if the most significant bit of ctFlags is clear. It’s ignored if the most significant bit of ctFlags is set. The value field is used as an index into a palette if the next most significant bit of ctFlags is set, in which case the rgb field is ignored. See the discussion of the ctFlags field earlier in this Note for more details.
  4723. Warning:    Color QuickDraw’s text-drawing routines assume that the color table of the destination graphics environment has the maximum number of colors for the pixel depth of the graphics environment, and that white is the first entry in the color table and black is the last entry. If these conditions aren’t satisfied, then the resulting image is unpredictable.
  4724. The code fragment in Listing 6 shows how to allocate a 256-entry color table from scratch. Color tables have a variable size, so the _NewHandle call has to calculate the size of the ColorTable record plus the maximum number of color table entries for the pixel depth multiplied by the size of a ColorSpec record. kNumColors - 1 is used in the calculation because the size of the ColorTable record includes the size of one ColorSpec entry in most development environments.
  4725. MPW Pascal Listing 6
  4726. CONST
  4727.    kNumColors = 256; {Number of color table entries}
  4728. VAR
  4729.    newColors: CTabHandle; {Handle to the new color table}
  4730.    index:     Integer;    {Index into the table of colors}
  4731. (* Allocate memory for the color table *)
  4732. newColors := CTabHandle(NewHandleClear(SizeOf (ColorTable) +
  4733.       SizeOf(ColorSpec) * (kNumColors - 1)));
  4734. IF newColors <> NIL THEN
  4735.    BEGIN
  4736.       (* Initialize the fields *)
  4737.       newColors^^.ctSeed := GetCTSeed;
  4738.       newColors^^.ctFlags := 0;
  4739.       newColors^^.ctSize := kNumColors - 1;
  4740.       (* Initialize the table of colors *)
  4741.       FOR index := 0 TO kNumColors - 1 DO
  4742.          BEGIN
  4743.             newColors^^.ctTable[index].value := index;
  4744.             newColors^^.ctTable[index].rgb.red := someRedValue;
  4745.             newColors^^.ctTable[index].rgb.green := someGreenValue;
  4746.             newColors^^.ctTable[index].rgb.blue := someBlueValue
  4747.          END
  4748.    END
  4749. MPW C Listing 6
  4750. #define kNumColors 256 /* Number of color table entries */
  4751. CTabHandle newColors; /* Handle to the new color table */
  4752. short      index;     /* Index into the table of colors */
  4753. /* Allocate memory for the color table */
  4754. newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) +
  4755.         sizeof (ColorSpec) * (kNumColors - 1) );
  4756. if (newColors != nil)
  4757. {
  4758.     /* Initialize the fields */
  4759.     (**newColors).ctSeed = GetCTSeed();
  4760.     (**newColors).ctFlags = 0;
  4761.     (**newColors).ctSize = kNumColors - 1;
  4762.     /* Initialize the table of colors */
  4763.     for (index = 0; index < kNumColors; index++)
  4764.     {
  4765.         (**newColors).ctTable[index].value = index;
  4766.         (**newColors).ctTable[index].rgb.red = someRedValue;
  4767.         (**newColors).ctTable[index].rgb.green = someGreenValue;
  4768.         (**newColors).ctTable[index].rgb.blue = someBlueValue;
  4769.     }
  4770. }
  4771. Changing Your Environment
  4772. After you create an off-screen graphics environment with certain dimensions, you might later want to change its size, depth, or color table without creating a completely new graphics environment from scratch and without needing to redraw the existing image. The UpdateOffScreen routine in Listing 7 shows just one way to do this. It takes the same parameters that CreateOffScreen (defined in Listing 1) does, but instead of creating a new CGrafPort and GDevice, it alters the ones that you pass through the updPort and updGDevice parameters. If the newBounds parameter specifies an empty rectangle, then the existing boundary rectangle for the off-screen graphics environment is used. Similarly, if newDepth is zero, then the existing depth is used; and if the newColors parameter is NIL, then the existing color table is used. UpdateOffScreen alters the given CGrafPort and GDevice to the new settings, but it completely replaces the PixMap. After all the alterations are made, the old PixMap’s image is copied to the new PixMap’s image, and then the old PixMap and its image are disposed.
  4773. MPW Pascal Listing 7
  4774. FUNCTION UpdateOffScreen(
  4775.    newBounds:  Rect;       {New bounding rectangle of off-screen}
  4776.    newDepth:   Integer;    {New number of bits per pixel in off-screen}
  4777.    newColors:  CTabHandle; {New color table to assign to off-screen}
  4778.    updPort:    CGrafPtr;   {Returns a pointer to the updated CGrafPort}
  4779.    updGDevice: GDHandle    {Returns a handle to the updated GDevice}
  4780.    ): OSErr;
  4781.    CONST
  4782.       kMaxRowBytes = $3FFE; {Maximum number of bytes per row of pixels}
  4783.    VAR
  4784.       newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}
  4785.       oldPixMap:   PixMapHandle; {Handle to the old off-screen PixMap}
  4786.       bounds:      Rect;         {Boundary rectangle of off-screen}
  4787.       depth:       Integer;      {Depth of the off-screen PixMap}
  4788.       bytesPerRow: Integer;      {Number of bytes per row in the PixMap}
  4789.       colors:      CTabHandle;   {Colors for the off-screen PixMap}
  4790.       savedFore:   RGBColor;     {Saved foreground color}
  4791.       savedBack:   RGBColor;     {Saved background color}
  4792.       aColor:      RGBColor;     {Used to set foreground and background color}
  4793.       qdVersion:   LongInt;      {Version of QuickDraw currently in use}
  4794.       savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}
  4795.       savedDevice: GDHandle;     {Handle to GDevice used for save/restore}
  4796.       savedState:  SignedByte;   {Saved state of color table handle}
  4797.       error:       OSErr;        {Returns error code}
  4798. BEGIN
  4799.    (* Initialize a few things before we begin *)
  4800.    newPixMap := NIL;
  4801.    error := noErr;
  4802.    (* Keep the old bounds rectangle, or get the new one *)
  4803.    IF EmptyRect(newBounds) THEN
  4804.       bounds := updPort^.portRect
  4805.    ELSE
  4806.       bounds := newBounds;
  4807.    (* Keep the old depth, or get the old one *)
  4808.    IF newDepth = 0 THEN
  4809.       depth := updPort^.portPixMap^^.pixelSize
  4810.    ELSE
  4811.       depth := newDepth;
  4812.    (* Get the old clut, or save new clut’s state and make it nonpurgeable *)
  4813.    IF newColors = NIL THEN
  4814.       colors := updPort^.portPixMap^^.pmTable
  4815.    ELSE
  4816.       BEGIN
  4817.          savedState := HGetState(Handle(newColors));
  4818.          HNoPurge(Handle(newColors));
  4819.          colors := newColors;
  4820.       END;
  4821.    (* Calculate the number of bytes per row in the off-screen PixMap *)
  4822.    bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  4823.    (* Get the current QuickDraw version *)
  4824.    error := Gestalt (gestaltQuickdrawVersion, qdVersion);
  4825.    error := noErr;
  4826.    (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)
  4827.    IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR
  4828.          (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN
  4829.       BEGIN
  4830.          (* Maximum number of bytes per row is 16,382; make sure within range *)
  4831.          IF bytesPerRow <= kMaxRowBytes THEN
  4832.             BEGIN
  4833.                (* Make sure a color table is provided if the depth is indexed *)
  4834.                IF depth <= 8 THEN
  4835.                   IF colors = NIL THEN
  4836.                      (* Indexed depth and clut is NIL; is parameter error *)
  4837.                      error := paramErr;
  4838.             END
  4839.          ELSE
  4840.             (* # of bytes per row is more than 16,382; is parameter error *)
  4841.             error := paramErr;
  4842.       END
  4843.    ELSE
  4844.       (* Pixel depth isn’t valid; is parameter error *)
  4845.       error := paramErr;
  4846.    (* If sanity checks succeed, attempt to update the graphics environment *)
  4847.    IF error = noErr THEN
  4848.       BEGIN
  4849.          (* Allocate a new PixMap *)
  4850.          newPixMap := PixMapHandle(NewHandleClear(SizeOf(PixMap)));
  4851.          IF newPixMap <> NIL THEN
  4852.               BEGIN
  4853.                (* Initialize the new PixMap for off-screen drawing *)
  4854.                error := SetUpPixMap(depth, bounds, colors, bytesPerRow,
  4855.                      newPixMap);
  4856.                IF error = noErr THEN
  4857.                   BEGIN
  4858.                      (* Save old PixMap and install new, initialized one *)
  4859.                      oldPixMap := updPort^.portPixMap;
  4860.                      updPort^.portPixMap := newPixMap;
  4861.                      (* Save current port & GDevice; set ones we’re updating *)
  4862.                      GetPort(savedPort);
  4863.                      savedDevice := GetGDevice;
  4864.                      SetPort(GrafPtr(updPort));
  4865.                      SetGDevice(updGDevice);
  4866.                      (* Set portRect, visRgn, clipRgn to given bounds rect *)
  4867.                      updPort^.portRect := bounds;
  4868.                      RectRgn(updPort^.visRgn, bounds);
  4869.                      ClipRect(bounds);
  4870.                      (* Update the GDevice *)
  4871.                      IF newPixMap^^.pixelSize <= 8 THEN
  4872.                         updGDevice^^.gdType := clutType
  4873.                      ELSE
  4874.                         updGDevice^^.gdType := directType;
  4875.                      updGDevice^^.gdPMap := newPixMap;
  4876.                      updGDevice^^.gdRect := newPixMap^^.bounds;
  4877.                      (* Set color-device bit if PixMap isn’t black & white *)
  4878.                      IF newPixMap^^.pixelSize > 1 THEN
  4879.                         SetDeviceAttribute(updGDevice, gdDevType, TRUE);
  4880.                      else
  4881.                         SetDeviceAttribute(updGDevice, gdDevType, FALSE);
  4882.                      (* Save current fore/back colors and set to B&W *)
  4883.                      GetForeColor(savedFore);
  4884.                      GetBackColor(savedBack);
  4885.                      aColor.red := 0; aColor.green := 0; aColor.blue := 0;
  4886.                      RGBForeColor(aColor);
  4887.                      aColor.red := $FFFF;
  4888.                      aColor.green := $FFFF;
  4889.                      aColor.blue := $FFFF;
  4890.                      RGBBackColor(aColor);
  4891.                      (* Copy old image to the new graphics environment *)
  4892.                      HLock(Handle(oldPixMap));
  4893.                      CopyBits(BitMapPtr(oldPixMap^)^, GrafPtr(updPort)^.portBits,
  4894.                            oldPixMap^^.bounds, updPort^.portRect,
  4895.                            srcCopy, NIL);
  4896.                      HUnlock(Handle(oldPixMap));
  4897.                      (* Restore the foreground/background color *)
  4898.                      RGBForeColor(savedFore);
  4899.                      RGBBackColor(savedBack);
  4900.                      (* Restore the saved port *)
  4901.                      SetPort(savedPort);
  4902.                      SetGDevice(savedDevice);
  4903.                      (* Get rid of the old PixMap and its dependents *)
  4904.                      DisposPtr(oldPixMap^^.baseAddr);
  4905.                      DisposeCTable(oldPixMap^^.pmTable);
  4906.                      DisposHandle(Handle(oldPixMap));
  4907.                   END;
  4908.             END
  4909.          ELSE
  4910.               error := MemError;
  4911.      END;
  4912.    (* Restore the given state of the color table *)
  4913.    IF colors <> NIL THEN
  4914.       HSetState(Handle(colors), savedState);
  4915.    (* One Last Look Around The House Before We Go… *)
  4916.    IF error <> noErr THEN
  4917.       BEGIN
  4918.          IF newPixMap <> NIL THEN
  4919.             BEGIN
  4920.                IF newPixMap^^.pmTable <> NIL THEN
  4921.                   DisposCTable(newPixMap^^.pmTable);
  4922.                IF newPixMap^^.baseAddr <> NIL THEN
  4923.                   DisposPtr(newPixMap^^.baseAddr);
  4924.                DisposHandle(Handle(newPixMap));
  4925.             END;
  4926.       END;
  4927.    UpdateOffScreen := error;
  4928. END;
  4929. MPW C Listing 7
  4930. #define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */
  4931. OSErr UpdateOffScreen(
  4932.     Rect       *newBounds, /* New bounding rectangle of off-screen */
  4933.     short      newDepth,   /* New number of bits per pixel in off-screen */
  4934.     CTabHandle newColors,  /* New color table to assign to off-screen */
  4935.     CGrafPtr   updPort,    /* Returns a pointer to the updated CGrafPort */
  4936.     GDHandle   updGDevice) /* Returns a handle to the updated GDevice */
  4937. {
  4938.     PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */
  4939.     PixMapHandle oldPixMap;   /* Handle to the old off-screen PixMap */
  4940.     Rect         bounds;      /* Boundary rectangle of off-screen */
  4941.     short        depth;       /* Depth of the off-screen PixMap */
  4942.     short        bytesPerRow; /* Number of bytes per row in the PixMap */
  4943.     CTabHandle   colors;      /* Colors for the off-screen PixMap */
  4944.     RGBColor     savedFore;   /* Saved foreground color */
  4945.     RGBColor     savedBack;   /* Saved background color */
  4946.     RGBColor     aColor;      /* Used to set foreground and background color */
  4947.     long         qdVersion;   /* Version of QuickDraw currently in use */
  4948.     GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */
  4949.     GDHandle     savedDevice; /* Handle to GDevice used for save/restore */
  4950.     SignedByte   savedState;  /* Saved state of color table handle */
  4951.     OSErr        error;       /* Returns error code */
  4952.     /* Initialize a few things before we begin */
  4953.     newPixMap = nil;
  4954.     error = noErr;
  4955.     /* Keep the old bounds rectangle, or get the new one */
  4956.     if (EmptyRect( newBounds ))
  4957.         bounds = updPort->portRect;
  4958.     else
  4959.         bounds = *newBounds;
  4960.     /* Keep the old depth, or get the old one */
  4961.     if (newDepth == 0)
  4962.         depth = (**updPort->portPixMap).pixelSize;
  4963.     else
  4964.         depth = newDepth;
  4965.     /* Get the old clut, or save new clut’s state and make it nonpurgeable */
  4966.     if (newColors == nil)
  4967.         colors = (**updPort->portPixMap).pmTable;
  4968.     else
  4969.     {
  4970.         savedState = HGetState( (Handle)newColors );
  4971.         HNoPurge( (Handle)newColors );
  4972.         colors = newColors;
  4973.     }
  4974.     /* Calculate the number of bytes per row in the off-screen PixMap */
  4975.     bytesPerRow = ((depth * (bounds.right - bounds.left) + 31) >> 5) << 2;
  4976.     /* Get the current QuickDraw version */
  4977.     (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );
  4978.     /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */
  4979.     if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  4980.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  4981.     {
  4982.         /* Maximum number of bytes per row is 16,382; make sure within range */
  4983.         if (bytesPerRow <= kMaxRowBytes)
  4984.         {
  4985.             /* Make sure a color table is provided if the depth is indexed */
  4986.             if (depth <= 8)
  4987.                 if (colors == nil)
  4988.                     /* Indexed depth and clut is NIL; is parameter error */
  4989.                     error = paramErr;
  4990.         }
  4991.         else
  4992.             /* # of bytes per row is more than 16,382; is parameter error */
  4993.             error = paramErr;
  4994.     }
  4995.     else
  4996.         /* Pixel depth isn’t valid; is parameter error */
  4997.         error = paramErr;
  4998.     /* If sanity checks succeed, attempt to create a new graphics environment */
  4999.     if (error == noErr)
  5000.     {
  5001.         /* Allocate a new PixMap */
  5002.         newPixMap = (PixMapHandle)NewHandleClear( sizeof (PixMap) );
  5003.         if (newPixMap != nil)
  5004.         {
  5005.             /* Initialize the new PixMap for off-screen drawing */
  5006.             error = SetUpPixMap( depth, &bounds, colors, bytesPerRow, newPixMap );
  5007.             if (error == noErr)
  5008.             {
  5009.                 /* Save the old PixMap and install the new, initialized one */
  5010.                 oldPixMap = updPort->portPixMap;
  5011.                 updPort->portPixMap = newPixMap;
  5012.                 /* Save current port & GDevice and set ones we’re updating */
  5013.                 GetPort( &savedPort );
  5014.                 savedDevice = GetGDevice();
  5015.                 SetPort( (GrafPtr)updPort );
  5016.                 SetGDevice( updGDevice );
  5017.                 /* Set portRect, visRgn, and clipRgn to the given bounds rect */
  5018.                 updPort->portRect = bounds;
  5019.                 RectRgn( updPort->visRgn, &bounds );
  5020.                 ClipRect( &bounds );
  5021.                 /* Update the GDevice */
  5022.                 if ((**newPixMap).pixelSize <= 8)
  5023.                     (**updGDevice).gdType = clutType;
  5024.                 else
  5025.                     (**updGDevice).gdType = directType;
  5026.                 (**updGDevice).gdPMap = newPixMap;
  5027.                 (**updGDevice).gdRect = (**newPixMap).bounds;
  5028.                 /* Set color-device bit if PixMap isn’t black & white */
  5029.                 if ((**newPixMap).pixelSize > 1)
  5030.                     SetDeviceAttribute( updGDevice, gdDevType, true );
  5031.                 else
  5032.                     SetDeviceAttribute( updGDevice, gdDevType, false );
  5033.                 /* Save current foreground/background colors and set to B&W */
  5034.                 GetForeColor( &savedFore );
  5035.                 GetBackColor( &savedBack );
  5036.                 aColor.red = aColor.green = aColor.blue = 0;
  5037.                 RGBForeColor( &aColor );
  5038.                 aColor.red = aColor.green = aColor.blue = 0xFFFF;
  5039.                 RGBBackColor( &aColor );
  5040.                 /* Copy old image to the new graphics environment */
  5041.                 HLock( (Handle)oldPixMap );
  5042.                 CopyBits( (BitMapPtr)*oldPixMap, &((GrafPtr) updPort)->portBits,
  5043.                         &(**oldPixMap).bounds, &updPort->portRect,
  5044.                         srcCopy, nil );
  5045.                 HUnlock( (Handle)oldPixMap );
  5046.                 /* Restore the foreground/background color */
  5047.                 RGBForeColor( &savedFore );
  5048.                 RGBBackColor( &savedBack );
  5049.                 /* Restore the saved port */
  5050.                 SetPort( savedPort );
  5051.                 SetGDevice( savedDevice );
  5052.                 /* Get rid of the old PixMap and its dependents */
  5053.                 DisposPtr( (**oldPixMap).baseAddr );
  5054.                 DisposeCTable( (**oldPixMap).pmTable ) ;
  5055.                 DisposHandle( (Handle)oldPixMap );
  5056.             }
  5057.         }
  5058.         else
  5059.             error = MemError();
  5060.     }
  5061.     /* Restore the given state of the color table */
  5062.     if (colors != nil)
  5063.         HSetState( (Handle)colors, savedState );
  5064.     /* One Last Look Around The House Before We Go… */
  5065.     if (error != noErr)
  5066.     {
  5067.         /* Some error occurred; dispose of everything we allocated */
  5068.         if (newPixMap != nil)
  5069.         {
  5070.             if ((**newPixMap).pmTable)
  5071.                 DisposCTable( (**newPixMap).pmTable );
  5072.             if ((**newPixMap).baseAddr)
  5073.                 DisposPtr ( (**newPixMap).baseAddr );
  5074.             DisposHandle( (Handle)newPixMap );
  5075.         }
  5076.     }
  5077.     return error;
  5078. }
  5079. UpdateOffScreen begins by checking the boundary rectangle, depth, or color table for emptiness, zero, or NIL, respectively. If any these satisfy that condition, then the existing characteristic is used. Next, the same sanity check that CreateOffScreen uses is done. If this sanity check succeeds, then a new PixMap is allocated, and then it’s initialized by the SetUpPixMap routine that’s given in Listing 2 which gives the new PixMap a new pixel image and its own copy of the color table. This new PixMap is installed into the CGrafPort after saving the reference to the old PixMap. Then, the portRect, visRgn, and clipRgn of the CGrafPort are set to the new boundary rectangle, as is the gdRect of the GDevice. The gdType of the GDevice is set either for the indexed-color or direct-color model, the gdPMap is set to the new PixMap, and the device attributes are set according to the pixel depth. Details about the settings for the CGrafPort and GDevice are in “Building the CGrafPort” and “Building the GDevice,” respectively, earlier in this Note.
  5080. At this point, the off-screen graphics environment is ready with its new characteristics, but it has garbage for an image because nothing has been drawn into it yet. The old PixMap, pixel image, and color table are still around, so _CopyBits transfers the old image into the altered graphics environment. _CopyBits handles the mapping from the old image’s characteristics to the new characteristics, so the altered graphics environment gets the best possible representation of the old image according to its new characteristics.
  5081. Changing the Off-Screen Color Table
  5082. Sometimes, it’s useful to change some or all of the colors in an off-screen color table, or to replace the off-screen color table with another one, so that the existing image in an indexed-color graphics environment appears with new colors. For example, if you had an off-screen image of a blue car and wanted to see what it looked like in green, you could change all of the shades of blue in the off-screen color table to green, and then _CopyBits the image to the screen. Notice that this is different from calling the UpdateOffScreen routine in the previous section with a different color table. That routine tries to reproduce the colors from the original image as best it can in the new set of colors. This section discusses the case in which you want the image’s colors to change.
  5083. The most obvious part of doing this is simply to get the color table from the off-screen pixel map’s pmTable field and modify the entries, or to dispose of the off-screen graphics environment’s current color table and assign the new one to it. There’s one more step to complete the process though. The discussion about GDevice records in “The Building Blocks” in this Note discusses inverse tables and how they go hand-in-hand with color tables. If you alter or replace the color table, you have to make sure that the inverse table of the off-screen drawing environment is rebuilt according to the new colors because Color QuickDraw uses that inverse table to know what pixel values to use for the specified color. You don’t have to rebuild the inverse table explicitly as long as you tell Color QuickDraw that the color table changed. To do this, all you have to do is make sure that the ctSeed of the changed or altered color table is set to a new value. And to do this, you can simply call _CTabChanged, which is documented on page 17-26 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI. _CTabChanged is available beginning with 32-Bit QuickDraw and it’s available in system software version 7.0. If this routine isn’t available, then you can still tell Color QuickDraw that the color table has been changed by calling _GetCTSeed and assigning its result directly to your new color table’s ctSeed field.
  5084. The next time you draw into this off-screen drawing environment, Color QuickDraw checks the ctSeed of the environment’s color table against the iTabSeed of the inverse table of the environment’s GDevice. Because you changed the ctSeed of the color table either through _CTabChanged or _GetCTSeed, these two seeds are different so Color QuickDraw automatically rebuilds the inverse table of the current GDevice and then it copies the ctSeed of the color table to the iTabSeed of the rebuilt inverse table. Then drawing continues normally.
  5085. Follow That Screen!
  5086. One common need of off-screen graphics environments is that they have a depth and color table that matches a screen. The CreateOffScreen routine requires a color table for indexed-color environments, and a pixel depth. Because there can be more than one screen attached to a Macintosh system, you have to decide which screen’s depth and color table you should use. Typically, the depth and color table of the deepest screen that contains the area that you’re interested in (probably the area of a window) is used. Another option is to use the depth and color table of the screen that has the largest area of intersection with the area that you’re interested in. To find the depth and color table of the screen on which you want to base an off-screen graphics environment, you must use the list of graphics devices for all screens which is maintained by the system. Every GDevice record for a screen has a handle to that screen’s PixMap, and you can find the screen’s depth and color table there.
  5087. Listing 8 shows a routine called CreateScreenOffScreen which creates an off-screen graphics environment that has the depth and color table of a selected screen. The first parameter, bounds, specifies the rectangular part of the screen area in which you’re interested in global coordinates. The screenOption parameter specifies how you want the screen to be chosen. If you pass kDeepestScreen in this parameter, CreateScreenOffScreen creates the new off-screen graphics environment with the depth and color table of the deepest screen that intersects the bounds rectangle. If you instead pass kLargestScreenArea, then the new off-screen graphics environment is created with the depth and color table of the screen with the largest area of intersection with the bounds rectangle.
  5088. MPW Pascal Listing 8
  5089. TYPE
  5090.    ScreenOpt = (kDeepestScreen, kLargestAreaScreen);
  5091. FUNCTION CreateScreenOffScreen(
  5092.    bounds:         Rect;      {Global rectangle of part of screen to save}
  5093.    screenOption:   ScreenOpt; {Use deepest or largest intersection area screen?}
  5094.    VAR retPort:    CGrafPtr;  {Returns a pointer to the new CGrafPort}
  5095.    VAR retGDevice: GDHandle   {Returns a handle to the new GDevice}
  5096.    ): OSErr;
  5097.    VAR
  5098.       baseGDevice:  GDHandle;     {GDevice to base off-screen on}
  5099.       aGDevice:     GDHandle;     {Handle to each GDevice in the GDevice list}
  5100.       basePixMap:   PixMapHandle; {baseGDevice’s PixMap}
  5101.       maxArea:      LongInt;      {Largest intersection area found}
  5102.       area:         LongInt;      {Area of rectangle of intersection}
  5103.       commonRect:   Rect;         {Rectangle of intersection}
  5104.       normalBounds: Rect;         {bounds rectangle normalized to (0, 0)}
  5105.       error:        Integer;      {Error code}
  5106. BEGIN
  5107.    error := noErr;
  5108.    (* Different screen options require different algorithms *)
  5109.    IF screenOption = kDeepestScreen THEN
  5110.       (* Graphics Devices Manager tells us the deepest intersecting screen *)
  5111.       baseGDevice := GetMaxDevice(bounds)
  5112.    ELSE IF screenOption = kLargestAreaScreen THEN
  5113.       BEGIN
  5114.          (* Get a handle to the first GDevice in the GDevice list *)
  5115.          aGDevice := GetDeviceList;
  5116.     
  5117.          (* Keep looping until all GDevices have been checked *)
  5118.          maxArea := 0;
  5119.          baseGDevice := NIL;
  5120.          WHILE aGDevice <> NIL DO
  5121.             BEGIN
  5122.                (* Check to see whether screen rectangle and bounds intersect *)
  5123.                IF SectRect(aGDevice^^.gdRect, bounds, commonRect) THEN
  5124.                   BEGIN
  5125.                      (* Calculate area of intersection *)
  5126.                      area := LongInt(commonRect.bottom - commonRect.top) *
  5127.                            LongInt(commonRect.right - commonRect.left);
  5128.                      (* Keep track of largest area of intersection so far *)
  5129.                      IF area > maxArea THEN
  5130.                         BEGIN
  5131.                            maxArea := area;
  5132.                            baseGDevice := aGDevice;
  5133.                         END;
  5134.                   END;
  5135.                (* Go to the next GDevice in the GDevice list *)
  5136.                aGDevice := GetNextDevice(aGDevice);
  5137.             END;
  5138.       END
  5139.    ELSE
  5140.       error := paramErr;
  5141.    (* If no screens intersect the bounds, baseDevice is NIL *)
  5142.    IF (baseGDevice <> NIL) AND (error = noErr) THEN
  5143.       BEGIN
  5144.          (* Normalize the bounds rectangle *)
  5145.          normalBounds := bounds;
  5146.          OffsetRect(normalBounds, -normalBounds.left, -normalBounds.top);
  5147.          (* Create off-screen graphics environment w/ depth, clut of screen *)
  5148.          basePixMap := baseGDevice^^.gdPMap;
  5149.          error := CreateOffScreen(normalBounds, basePixMap^^.pixelSize,
  5150.                basePixMap^^.pmTable, retPort, retGDevice);
  5151.       END;
  5152.    CreateScreenOffScreen := error;
  5153. END;
  5154. MPW C Listing 8
  5155. enum
  5156. {
  5157.     kDeepestScreen,
  5158.     kLargestAreaScreen,
  5159. };
  5160. OSErr CreateScreenOffScreen(
  5161.     Rect     *bounds,      /* Global rectangle of part of screen to save */
  5162.     short    screenOption, /* Use deepest or largest intersection area screen */
  5163.     CGrafPtr *retPort,     /* Returns a pointer to the new CGrafPort */
  5164.     GDHandle *retGDevice)  /* Returns a handle to the new GDevice */
  5165. {
  5166.     GDHandle     baseGDevice;  /* GDevice to base off-screen on */
  5167.     GDHandle     aGDevice;     /* Handle to each GDevice in the GDevice list */
  5168.     PixMapHandle basePixMap;   /* baseGDevice’s PixMap */
  5169.     long         maxArea;      /* Largest intersection area found */
  5170.     long         area;         /* Area of rectangle of intersection */
  5171.     Rect         commonRect;   /* Rectangle of intersection */
  5172.     Rect         normalBounds; /* bounds rectangle normalized to (0, 0) */
  5173.     short        error;        /* Error code */
  5174.     error = noErr;
  5175.     /* Different screen options require different algorithms */
  5176.     if (screenOption == kDeepestScreen)
  5177.         /* Graphics Devices Manager tells us the deepest intersecting screen */
  5178.         baseGDevice = GetMaxDevice( bounds );
  5179.     else if (screenOption == kLargestAreaScreen)
  5180.     {
  5181.         /* Get a handle to the first GDevice in the GDevice list */
  5182.         aGDevice = GetDeviceList();
  5183.     
  5184.         /* Keep looping until all GDevices have been checked */
  5185.         maxArea = 0;
  5186.         baseGDevice = nil;
  5187.         while (aGDevice != nil)
  5188.         {
  5189.             /* Check to see whether screen rectangle and bounds intersect */
  5190.             if (SectRect( &(**aGDevice).gdRect, bounds, &commonRect ))
  5191.             {
  5192.                 /* Calculate area of intersection */
  5193.                 area = (long)(commonRect.bottom - commonRect.top) *
  5194.                        (long)(commonRect.right - commonRect.left);
  5195.                 /* Keep track of largest area of intersection found so far */
  5196.                 if (area > maxArea)
  5197.                 {
  5198.                     maxArea = area;
  5199.                     baseGDevice = aGDevice;
  5200.                 }
  5201.             }
  5202.             /* Go to the next GDevice in the GDevice list */
  5203.             aGDevice = GetNextDevice( aGDevice );
  5204.         }
  5205.     }
  5206.     else
  5207.         error = paramErr;
  5208.     /* If no screens intersect the bounds, baseDevice is NIL */
  5209.     if (baseGDevice != nil && error == noErr)
  5210.     {
  5211.         /* Normalize the bounds rectangle */
  5212.         normalBounds = *bounds;
  5213.         OffsetRect( &normalBounds, -normalBounds.left, -normalBounds.top );
  5214.         /* Create off-screen graphics environment w/ depth, clut of screen */
  5215.         basePixMap = (**baseGDevice).gdPMap;
  5216.         error = CreateOffScreen( &normalBounds, (**basePixMap).pixelSize,
  5217.                 (**basePixMap).pmTable, retPort, retGDevice );
  5218.     }
  5219.     return error;
  5220. }
  5221. Finding the deepest screen that intersects an on-screen area is trivially easy because there’s a Graphics Devices Manager routine that finds it called _GetMaxDevice which is documented on page 21-22 of the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI. The rectangle in global coordinates of the screen area you’re interested in is passed to _GetMaxDevice, and it returns a handle to the deepest screen that intersects that area, even if the area of intersection is as small as one pixel. If no screens intersect that area, then _GetMaxDevice returns NIL.
  5222. Finding the GDevice of the screen that has the maximum area of intersection with the screen area you’re interested in isn’t quite so easy because there’s no single Graphics Devices Manager routine to find this GDevice; you have to search the GDevice list yourself. You can get a handle to the first GDevice in the list by calling _GetDeviceList, and you can get a handle to each successive GDevice by calling _GetNextDevice. _GetDeviceList is documented on pages 21-21 through 21-22 of the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI, and _GetNextDevice is documented on page 21-22 of the same chapter. For each GDevice in the list, the area of intersection between the bounds and the gdRect of the GDevice is calculated. If the calculated area is the largest area of intersection found so far, then that area and the GDevice of that screen are remembered.
  5223. Once a winning GDevice has been chosen, either by being the deepest intersecting GDevice or the GDevice with the largest intersecting area, then CreateOffScreen routine is called with the pixel depth and color table of the PixMap of the GDevice, and the bounds rectangle normalized so that its top-left coordinate has the coordinates (0, 0). CreateOffScreen returns with the new off-screen graphics environment, and CreateScreenOffScreen returns this to the caller.
  5224. Choosing Your Off-Screen Memory
  5225. The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment with its pixel image allocated as a nonrelocatable block in the application’s heap. But this isn’t the only way that the pixel image can be allocated. Pixel images can be big, and big blocks of nonrelocatable memory in your heap can be expensive in terms of performance, and they can cause a bad case of heap fragmentation. Why not put the pixel image in a relocatable block of memory instead? If there isn’t much free memory in your heap and if MultiFinder or system software version 7.0 is running, there’s memory that’s not being used by any open applications, called temporary memory (formerly called MultiFinder temporary memory). Why not use this area of memory for the pixel image? Some people have NuBus cards with plenty of memory on them. Why not move the pixel image out of the heaps altogether and instead use NuBus memory for the pixel image? All of these things can be done with simple modifications to what’s been discussed in this Note, and these modifications are discussed in the next few paragraphs.
  5226. How can pixel images be relocatable? After all, pixel images are referred to only by the baseAddr field of a PixMap, and the baseAddr is a pointer, not a handle. It’s true that while QuickDraw is being used to draw into a graphics environment, the pixel image had better not move or else QuickDraw will start drawing over the area of memory that the pixel image used to be rather than where it is. But if QuickDraw isn’t doing anything with the graphics environment, then it doesn’t care what happens to the pixel image as long as the baseAddr points to it once QuickDraw starts drawing into the graphics environment. This implies a strategy: allocate the pixel image as a relocatable block and let it float in the heap; when QuickDraw is about to to draw into the graphics environment or to copy from it, lock the pixel image and copy its master pointer into the baseAddr field of the PixMap; when the drawing or copying is finished, unlock the pixel image. There are many ways to implement this, and Listing 9 shows a code fragment for one very simple method.
  5227. MPW Pascal Listing 9
  5228.       ...
  5229.       (* Allocate the pixel image; use long multiplication to avoid overflow *)
  5230.       offBaseAddr := NewHandle(LongInt(bytesPerRow) * (bounds^.bottom -
  5231.             bounds^.top));
  5232.       IF offBaseAddr <> NIL THEN
  5233.          BEGIN
  5234.             (* Initialize fields common to indexed and direct PixMaps *)
  5235.             aPixMap^^.baseAddr := Ptr(offBaseAddr); (* Reference the image *)
  5236.       ...
  5237. PROCEDURE LockOffScreen(
  5238.    offScreenPort: CGrafPtr {Ptr to off-screen CGrafPort}
  5239.    );
  5240.    VAR
  5241.       offImageHnd: Handle; {Handle to the off-screen pixel image}
  5242. BEGIN
  5243.    (* Get the saved handle to the off-screen pixel image *)
  5244.    offImageHnd := Handle(offScreenPort^.portPixMap^^.baseAddr);
  5245.    (* Lock the handle to the pixel image *)
  5246.    HLock(offImageHnd);
  5247.    (* Put pixel image master pointer into baseAddr so that QuickDraw can use it *)
  5248.    offScreenPort^.portPixMap^^.baseAddr := offImageHnd^;
  5249. END;
  5250. PROCEDURE UnlockOffScreen(
  5251.    offScreenPort: CGrafPtr {Ptr to off-screen port}
  5252.    );
  5253.    VAR
  5254.       offImagePtr: Ptr;    {Pointer to the off-screen pixel image}
  5255.       offImageHnd: Handle; {Handle to the off-screen pixel image}
  5256. BEGIN
  5257.    (* Get the handle to the off-screen pixel image *)
  5258.    offImagePtr := offScreenPort^.portPixMap^^.baseAddr;
  5259.    offImageHnd := RecoverHandle(offImagePtr);
  5260.    (* Unlock the handle *)
  5261.    HUnlock(offImageHnd);
  5262.    (* Save the handle back in the baseAddr field *)
  5263.    offScreenPort^.portPixMap^^.baseAddr := Ptr(offImageHnd);
  5264. END;
  5265. MPW C Listing 9
  5266.         ...
  5267.         /* Allocate the pixel image; use long multiplication to avoid overflow */
  5268.         offBaseAddr = NewHandle( (unsigned long)bytesPerRow * (bounds->bottom -
  5269.                 bounds->top) );
  5270.         if (offBaseAddr != nil)
  5271.         {
  5272.             /* Initialize fields common to indexed and direct PixMaps */
  5273.             (**aPixMap).baseAddr = (Ptr)offBaseAddr; /* Reference the image */
  5274.         ...
  5275. void LockOffScreen(
  5276.     CGrafPtr offScreenPort) /* Pointer to the off-screen CGrafPort */
  5277. {
  5278.     Handle offImageHnd; /* Handle to the off-screen pixel image */
  5279.     /* Get the saved handle to the off-screen pixel image */
  5280.     offImageHnd = (Handle)(**offScreenPort->portPixMap).baseAddr;
  5281.     /* Lock the handle to the pixel image */
  5282.     HLock( offImageHnd );
  5283.     /* Put pixel image master pointer into baseAddr so that QuickDraw can use it */
  5284.     (**offScreenPort->portPixMap).baseAddr = *offImageHnd;
  5285. }
  5286. void UnlockOffScreen(
  5287.     CGrafPtr offScreenPort) /* Pointer to the off-screen CGrafPort */
  5288. {
  5289.     Ptr    offImagePtr; /* Pointer to the off-screen pixel image */
  5290.     Handle offImageHnd; /* Handle to the off-screen pixel image */
  5291.     /* Get the handle to the off-screen pixel image */
  5292.     offImagePtr = (**offScreenPort->portPixMap).baseAddr;
  5293.     offImageHnd = RecoverHandle( offImagePtr );
  5294.     /* Unlock the handle */
  5295.     HUnlock( offImageHnd );
  5296.     /* Save the handle back in the baseAddr field */
  5297.     (**offScreenPort->portPixMap).baseAddr = (Ptr)offImageHnd;
  5298. }
  5299. Listing 9 starts with a code fragment from the SetUpPixMap routine that’s modified so that it allocates a new handle for the off-screen pixel image instead of a new pointer. This handle is saved in the baseAddr field for now. When you’re about to draw into the off-screen graphics environment or to copy from it, the LockOffScreen routine in Listing 9 should be called with a pointer to the off-screen graphics environment’s CGrafPort as the parameter. It takes the handle to the pixel image from the baseAddr field of the off-screen graphics environment’s PixMap and passes it to _HLock which makes sure the pixel image can’t move in the heap. Then, the pixel image’s handle is dereferenced to get the master pointer to the pixel image, and this master pointer is copied into the baseAddr field. Now, QuickDraw can draw into or copy from the off-screen graphics environment.
  5300. When you’re finished drawing into the off-screen graphics environment, the pixel image should be unlocked, and the UnlockOffScreen routine in Listing 9 does this. The baseAddr field of the PixMap holds the pixel image’s master pointer, so this is passed to _RecoverHandle to get the pixel image’s handle. This handle is passed to _HUnlock to let the pixel image float in the heap again, and then this handle is saved in the baseAddr field.
  5301. One potentially useful addition to the LockOffScreen routine would be a call to _MoveHHi just before the call to _HLock. This helps reduce heap fragmentation while the pixel image is locked by moving it up as high in the heap as possible before locking it, allowing the other relocatable blocks to move without tripping over it. You have to be careful with _MoveHHi though because it not only moves the handle as high in the heap as possible, it moves other relocatable blocks out of the top of the heap to make room for the handle. This could involve moving huge amounts of memory, and it’s not unusual for _MoveHHi to take several seconds to do this.
  5302. How do you make an off-screen graphics environment that uses temporary memory for the pixel image? Temporary memory is allocated as handles, so there’s almost no difference between using temporary memory and using relocatable blocks in your own heap in the way that Listing 9 shows. All you have to do is replace the calls to _NewHandle, _HLock, and _HUnlock with calls to _TempNewHandle, _TempHLock, and _TempHUnlock. If temporary memory handles are real, then you don’t even have to replace the _HLock and _HUnlock calls—they work properly with temporary memory handles that are real.You can tell whether temporary memory handles are real or not by calling _Gestalt with the gestaltOSAttr selector. If the gestaltRealTempMemory bit is set, then all temporary memory handles are real. See the sections “About Temporary Memory” and “Using Temporary Memory” of Inside Macintosh Volume VI, pages 28-33 through 28-40.
  5303. How do you make an off-screen graphics environment that stores the pixel image on a NuBus memory card? The Macintosh Memory Manager doesn’t keep track of heaps on NuBus memory cards so it can’t be used to allocate memory on those cards, but if applications can use that card’s memory at will, then an application can set up the off-screen graphics environment with its pixel image in the NuBus card’s memory simply by setting the address of the card’s memory in the baseAddr field of the off-screen graphics environment’s PixMap instead of allocating anything.
  5304. If your NuBus memory card doesn’t require 32-bit addressing mode to access its memory, then setting the baseAddr to the address of the NuBus card’s memory is all you have to do. Some NuBus memory cards require its memory to be accessed in 32-bit addressing mode. Without 32-Bit QuickDraw, these memory cards can’t be used for storing the pixel image of an off-screen graphics environment because Color QuickDraw without 32-Bit QuickDraw always reads and writes pixel images in 24-bit addressing mode regardless of whether the pixel image is in main memory, on a NuBus video card, or on a NuBus memory card. With 32-Bit QuickDraw, Color QuickDraw automatically switches to 32-bit addressing mode before reading or writing a pixel image that’s on a video card. It won’t know to switch to 32-bit addressing mode if your off-screen graphics environment uses a pixel image on a NuBus memory card that’s not a video card, but you can tell it to make this switch by setting bit 2 of the pmVersion field of the PixMap for the off-screen graphics environment. This is normally done by logically ORing the pmVersion field with the predefined constant baseAddr32. See “About 32-Bit Addressing” in Issue 6 of develop, page 36, for more details about how QuickDraw handles addressing modes.
  5305. The GWorld Factor
  5306. In May 1989, 32-Bit QuickDraw was introduced as an extension to the system. While it had a lot of new features, the GWorld mechanism was the one that made the big news. GWorlds are off-screen graphics environments that you can have the system put together in one call. There’s no need for routines like CreateOffScreen, SetUpPixMap, or CreateGDevice—all of the off-screen graphics environment is set up with _NewGWorld. You can change most of its characteristics with _UpdateGWorld, set the current off-screen graphics environment with _SetGWorld, and get rid of the off-screen graphics environment with _DisposeGWorld. All the GWorld routines are described in the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI. As an example, Listing 10 shows the same routine as the ExerciseOffScreen routine that’s shown in Listing 5, but Listing 10 uses GWorlds rather than the do-it-yourself routines that are defined in this Note.
  5307. MPW Pascal Listing 10
  5308. PROCEDURE ExerciseOffScreen;
  5309.    CONST
  5310.       kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}
  5311.       rGrayClut  = 1600; {Resource ID of gray-scale clut}
  5312.       rColorClut = 1601; {Resource ID of full-color clut}
  5313.    VAR
  5314.       grayPort:    GWorldPtr;  {Graphics environment for gray off screen}
  5315.       colorPort:   GWorldPtr;  {Graphics environment for color off screen}
  5316.       savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  5317.       savedDevice: GDHandle;   {Handle to the saved color environment}
  5318.       offColors:   CTabHandle; {Colors for off-screen environments}
  5319.       offRect:     Rect;       {Rectangle of off-screen environments}
  5320.       circleRect:  Rect;       {Rectangles for circle-drawing}
  5321.       count:       Integer;    {Generic counter}
  5322.       aColor:      RGBColor;   {Color used for drawing off-screen}
  5323.       error:       OSErr;      {Error return from off-screen creation}
  5324. BEGIN
  5325.    (* Set up the rectangle for the off-screen graphics environments *)
  5326.    SetRect(offRect, 0, 0, 256, 256);
  5327.    (* Get the color table for the gray off-screen graphics environment *)
  5328.    offColors := GetCTable(rGrayClut);
  5329.    (* Create the gray off-screen graphics environment *)
  5330.    error := NewGWorld(grayPort, kOffDepth, offRect, offColors, NIL, []);
  5331.    IF error = noErr THEN
  5332.       BEGIN
  5333.          (* Get the color table for the color off-screen graphics environment *)
  5334.          offColors := GetCTable(rColorClut);
  5335.          (* Create the color off-screen graphics environment *)
  5336.          error := NewGWorld(colorPort, kOffDepth, offRect, offColors, NIL, []);
  5337.          IF error = noErr THEN
  5338.             BEGIN
  5339.                (* Save the current graphics environment *)
  5340.                GetGWorld(savedPort, savedDevice);
  5341.                (* Set the current graphics environment to the gray one *)
  5342.                SetGWorld(grayPort, NIL);
  5343.                (* Draw gray-scale ramp into the gray off-screen environment *)
  5344.                FOR count := 0 TO 255 DO
  5345.                   BEGIN
  5346.                      aColor.red := count * 257;
  5347.                      aColor.green := aColor.red;
  5348.                      aColor.blue := aColor.green;
  5349.                      RGBForeColor(aColor);
  5350.                      MoveTo(0, count);
  5351.                      LineTo(255, count);
  5352.                   END;
  5353.                (* Copy gray ramp into color off-screen colorized with green *)
  5354.                SetGWorld(colorPort, NIL);
  5355.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  5356.                RGBForeColor(aColor);
  5357.                CopyBits(GrafPtr(grayPort)^.portBits,
  5358.                      GrafPtr(colorPort)^.portBits,
  5359.                      grayPort^.portRect,
  5360.                      colorPort^.portRect,
  5361.                      srcCopy + ditherCopy, NIL);
  5362.                (* Draw red, green, and blue circles *)
  5363.                PenSize(8, 8);
  5364.                aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;
  5365.                RGBForeColor(aColor);
  5366.                circleRect := colorPort^.portRect;
  5367.                FrameOval(circleRect);
  5368.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  5369.                RGBForeColor(aColor);
  5370.                InsetRect(circleRect, 20, 20);
  5371.                FrameOval(circleRect);
  5372.                aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;
  5373.                RGBForeColor(aColor);
  5374.                InsetRect(circleRect, 20, 20);
  5375.                FrameOval(circleRect);
  5376.                (* Copy the color off-screen environment to the current port *)
  5377.                SetGWorld(savedPort, savedDevice);
  5378.                CopyBits(GrafPtr(colorPort)^.portBits,
  5379.                      savedPort^.portBits,
  5380.                      colorPort^.portRect,
  5381.                      savedPort^.portRect,
  5382.                      srcCopy, NIL);
  5383.                (* Dispose of the off-screen graphics environments *)
  5384.                DisposeGWorld grayPort);
  5385.                DisposeGWorld(colorPort);
  5386.             END;
  5387.       END;
  5388. END;
  5389. MPW C Listing 10
  5390. #define kOffDepth  8    /* Number of bits per pixel in off-screen environment */
  5391. #define rGrayClut  1600 /* Resource ID of gray-scale clut */
  5392. #define rColorClut 1601 /* Resource ID of full-color clut */
  5393. void ExerciseOffScreen()
  5394. {
  5395.     GWorldPtr  grayPort;    /* Graphics environment for gray off screen */
  5396.     GWorldPtr  colorPort;   /* Graphics environment for color off screen */
  5397.     CGrafPtr   savedPort;   /* Pointer to the saved graphics environment */
  5398.     GDHandle   savedDevice; /* Handle to the saved color environment */
  5399.     CTabHandle offColors;   /* Colors for off-screen environments */
  5400.     Rect       offRect;     /* Rectangle of off-screen environments */
  5401.     Rect       circleRect;  /* Rectangles for circle-drawing */
  5402.     short      count;       /* Generic counter */
  5403.     RGBColor   aColor;      /* Color used for drawing off-screen */
  5404.     OSErr      error;       /* Error return from off-screen creation */
  5405.     /* Set up the rectangle for the off-screen graphics environments */
  5406.     SetRect( &offRect, 0, 0, 256, 256 );
  5407.     /* Get the color table for the gray off-screen graphics environment */
  5408.     offColors = GetCTable( rGrayClut );
  5409.     /* Create the gray off-screen graphics environment */
  5410.     error = NewGWorld( &grayPort, kOffDepth, &offRect, offColors, nil, 0 );
  5411.     if (error == noErr)
  5412.     {
  5413.         /* Get the color table for the color off-screen graphics environment */
  5414.         offColors = GetCTable( rColorClut );
  5415.         /* Create the color off-screen graphics environment */
  5416.         error = NewGWorld( &colorPort, kOffDepth, &offRect, offColors, nil, 0 );
  5417.         if (error == noErr)
  5418.         {
  5419.             /* Save the current graphics environment */
  5420.             GetGWorld( &savedPort, &savedDevice );
  5421.             /* Set the current graphics environment to the gray one */
  5422.             SetGWorld( grayPort, nil );
  5423.             /* Draw gray-scale ramp into the gray off-screen environment */
  5424.             for (count = 0; count < 256; count++)
  5425.             {
  5426.                 aColor.red = aColor.green = aColor.blue = count * 257;
  5427.                 RGBForeColor( &aColor );
  5428.                 MoveTo( 0, count );
  5429.                 LineTo( 255, count );
  5430.             }
  5431.             /* Copy gray ramp into color off-screen colorized with green */
  5432.             SetGWorld( colorPort, nil );
  5433.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  5434.             RGBForeColor( &aColor );
  5435.             CopyBits( &((GrafPtr)grayPort)->portBits,
  5436.                     &((GrafPtr)colorPort)->portBits,
  5437.                     &grayPort->portRect,
  5438.                     &colorPort->portRect,
  5439.                     srcCopy | ditherCopy, nil );
  5440.             /* Draw red, green, and blue circles */
  5441.             PenSize( 8, 8 );
  5442.             aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;
  5443.             RGBForeColor( &aColor );
  5444.             circleRect = colorPort->portRect;
  5445.             FrameOval( &circleRect );
  5446.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  5447.             RGBForeColor( &aColor );
  5448.             InsetRect( &circleRect, 20, 20 );
  5449.             FrameOval( &circleRect );
  5450.             aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;
  5451.             RGBForeColor( &aColor );
  5452.             InsetRect( &circleRect, 20, 20 );
  5453.             FrameOval( &circleRect );
  5454.             /* Copy the color off-screen environment to the current port */
  5455.             SetGWorld( savedPort, savedDevice );
  5456.             CopyBits( &((GrafPtr)colorPort)->portBits,
  5457.                     &((GrafPtr)savedPort)->portBits,
  5458.                     &colorPort->portRect,
  5459.                     &savedPort->portRect,
  5460.                     srcCopy, nil );
  5461.             /* Dispose of the off-screen graphics environments */
  5462.             DisposeGWorld( grayPort );
  5463.             DisposeGWorld( colorPort );
  5464.         }
  5465.     }
  5466. }
  5467. _NewGWorld creates an off-screen graphics environment by creating a CGrafPort, PixMap, and GDevice—the same structures that you normally put together when you make an off-screen graphics environment yourself. In this aspect, and in fact in most aspects, there’s nothing magical about GWorlds. Do GWorlds make the CreateOffScreen, DisposeOffScreen, and their dependents useless? That depends on what your needs are. What follows are a few issues about off-screen drawing and how that determines whether you use your own routines, such as CreateOffScreen, to create and maintain off-screen graphics environments or whether you use GWorlds for the same purpose.
  5468. I Want the Best Performance!
  5469. As mentioned in the last paragraph, there’s nothing magical about GWorlds in most aspects. In one major aspect, there certainly is: the version of Color QuickDraw that runs with the 8•24 GC video card’s acceleration on knows about GWorlds and can cache their CGrafPort, PixMap, GDevice, inverse table, color table, and pixel image on the 8•24 GC card if there’s enough memory on it. When this is done, QuickDraw operations on the GWorld can be much faster than they’d normally be because the image data can stay in the card’s memory where the fast microprocessor is, and image data doesn’t have to move across NuBus in transfer operations between the GWorld and the screen. Additionally, these operations are executed asynchronously which increases the overall speed of your programs. For details about how the 8•24 GC card and GC QuickDraw work, see Guillermo Ortiz’s article, “Macintosh Display Card 8•24 GC: The Naked Truth,” in Issue 5 of develop.
  5470. 8•24 GC QuickDraw doesn’t know about the off-screen graphics environments that you create, so it doesn’t cache its structures. All QuickDraw commands that move image data between the off-screen graphics environment and the screen have to move the data across NuBus, and that slows down the operation in comparison to keeping all the image data on the card.
  5471. If you want the highest possible drawing and copying performance with the 8•24 GC card, you must use GWorlds for your off-screen graphics environments.
  5472. I Want to Use a NuBus Memory Card for My GWorld’s Off-Screen Pixel Image
  5473. One common desire is to use a NuBus memory card to hold a pixel image. Because GWorlds are so easy to set up, and because GWorlds have all the same parts that you can make for an off-screen graphics environment, it’s tempting to make a GWorld and then point the baseAddr of the GWorld’s PixMap at the NuBus card’s memory. But GWorlds are designed to be fairly atomic structures, so they can’t be changed in this way. You can change a GWorld’s dimensions, depth, and color table because there’s a routine (_UpdateGWorld) that is designed to change these things, but you can’t change the pixel image without risking future compatibility.
  5474. If you want to have an off-screen graphics environment use a NuBus video card to store the pixel image, you should set up your own off-screen graphics environment rather than use GWorlds. This is covered earlier in this Note in “Choosing Your Off-Screen Memory.”
  5475. I Want My Program to Work on All System Software Releases
  5476. GWorlds have been around since 32-Bit QuickDraw was released (while system software version 6.0.3 was current). Until system software version 7.0, 32-Bit QuickDraw was an optional part of the system, so you aren’t guaranteed use of GWorlds even under recent system software releases. Obviously, if GWorlds aren’t available and your program still has to work with off-screen graphics environments, then there’s no choice but to use your own routines for creating, maintaining, and disposing of off-screen graphics environments. What’s usually done in these cases is to check via _Gestalt whether GWorlds are available or not. If they aren’t, then you create your off-screen graphics environment with your own routines. If they are, then you can use GWorlds without having to take up memory with your code for creating off-screen graphics environments yourself.
  5477. Are We There Yet?
  5478. Reliable, understandable, and maintainable off-screen drawing routines means not taking short-cuts. The most common problems that people run into with off-screen drawing routines is the appearance of strange colors and the gradual degradation of reliability as the program does more off-screen drawing. Building an off-screen graphics environment out of a CGrafPort, GDevice, and PixMap or by using GWorlds, combined with an understanding of how Color QuickDraw uses off-screen graphics environments, helps get rid of these problems. Hopefully, this Note helps you understand these things so that you can get better programs out the door faster.
  5479. Further Reference:
  5480. •    Apple Computer, Inc., Inside Macintosh Volume I, Addison-Wesley, Reading, MA, 1985
  5481. •    Apple Computer, Inc., Inside Macintosh Volume V, Addison-Wesley, Reading, MA, 1988.
  5482. •    Apple Computer, Inc., Inside Macintosh Volume VI, Addison-Wesley, Reading, MA, 1991.
  5483. •    Knaster, S., Macintosh Programming Secrets, Addison-Wesley, Reading, MA, 1988.
  5484. •    Leak, B., “Realistic Color For Real-World Applications,” develop, January 1990, 4-21.
  5485. •    Ortiz, G., “Braving Offscreen GWorlds,” develop, January 1990, 28-40.
  5486. •    Ortiz, G., “Deaccelerated _CopyBits & 8•24 GC QuickDraw,” Macintosh Technical Note #289, January 1991.
  5487. •    Ortiz, G., “Macintosh Display Card 8•24 GC: The Naked Truth,”  develop, July 1990, 332-347.
  5488. •    Othmer, K., “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0,” develop, Spring 1991, 23-42.
  5489. •    Tanaka, F., “Of Time and Space and _CopyBits,” Macintosh Technical Note #277, June 1990.
  5490. •    Zap, J., F. Tanaka, J. Friedlander, and G. Jernigan, “Drawing Into an Off-Screen Bitmap,” Macintosh Technical Note #41, June 1990.
  5491. NuBus is a trademark of Texas Instruments.
  5492. Of Time and Space and _CopyBits
  5493. Imaging    M.IM.TimeSpaceCopyBits
  5494. Written by:    Forrest Tanaka    June 1990
  5495. This Technical Note describes the various factors that can influence the speed of _CopyBits so that developers can set up conditions to achieve the best performance for the particular situation.
  5496. Can You Influence the Speed of _CopyBits?
  5497. _CopyBits has never been an “easy” QuickDraw routine, like _LineTo or even _OpenPort.  Most programmers who are just beginning to adjust themselves to the Macintosh usually have to give _CopyBits a few tries before the right bits copy to the right places.  Even many who feel that they have become Macintosh programmers still see reflections in their monitors of furrows between their eyebrows as they begin to press the key labelled “C.”
  5498. _CopyBits is one of those routines that is so full of subtlety, it has the beginnings of something that could be considered to be personality.  One subtlety involves the second most important thought that’s on the minds of any computer programmer:  execution speed.  Why is _CopyBits fast?  Why is it slow?  Can I influence its speed?  Is there really a clandestine state of reason?  Is there a price to speed?
  5499. Influences on the Speed of _CopyBits
  5500. Yes, you can influence the speed of _CopyBits.  Yes, it’s even predictable.  And yes, it’s possible that you have to compromise to get the maximum speed.  This Note is intended to give you a deeper understanding of the ways that the speed of _CopyBits can be affected; and hopefully you can then set up conditions for a _CopyBits call without the disturbing notion that someone else might be doing the same thing just a little bit better than you.
  5501. This Note talks about every factor that affects the speed of _CopyBits that I can think of and that can be reasonably controlled by a programmer or the person using an application.  There are other factors not mentioned in this Note because I felt that they were just too esoteric to describe with any meaning.
  5502. In each case, this Note tries to give real-life examples showing the effect of each factor.  These examples are just to give you a relative idea of the importance of each effect.  In real life, the effects of the different factors give results that could be a lot different from the results presented in this Note.  Each example is based on 100 _CopyBits calls from an off-screen pixel map to the screen on a Macintosh IIcx with an Apple Extended Video Card which is running System Software 6.0.5 and 32-Bit QuickDraw 1.2.  The off-screen pixel map is eight bits deep with the standard eight-bit color table and 256 pixels high by 256 pixels wide.  The screen is also in eight-bit color mode.  Calling _CopyBits to copy the entire off-screen pixel map to the screen 100 times takes 204 ticks, and this Note refers to this figure as the “standard test.”  Since a tick on a Macintosh is approximately 1/60 of a second, the standard test runs at slightly less than 30 frames per second.  As this Note discusses each factor, it presents an example with that factor changing and all other factors remaining the same as the standard test, which allows you to compare performance of the changed factor to that of the standard test of 204 ticks.
  5503. What follows is a discussion of each factor that can influence the speed of _CopyBits, in no particular order.
  5504. Dimensions of the Copied Area
  5505. One of  the most obvious factors has to do with the dimensions of the copied area.  _CopyBits takes as parameters two rectangles which specify the portion of the source pixel map from which you want to copy and the portion of the destination pixel map to which you want to copy it.  All other factors being equal, the larger the rectangles, the more pixels _CopyBits has to copy and the longer it takes to do the job.  To keep _CopyBits as fast as possible, copy the smallest rectangle possible.
  5506. Modifying the standard test so that _CopyBits only copies a 128-pixel wide by 128-pixel tall area produces a result of 109 ticks, which compares to the 204 tick performance for a 256-pixel wide by 256-pixel tall area.
  5507. QuickDraw is usually faster drawing wide things than it is drawing tall things, because consecutive pixels in memory are displayed horizontally.  Drawing a series of pixels that are next to each other horizontally is easy because QuickDraw simply has to set consecutive memory locations, while drawing a series of pixels that are next to each other vertically is just a little bit harder because the address of each pixel must be calculated.  _CopyBits is no exception to this general rule; it copies a row of pixels, goes to the next row, copies that row, goes to the next row, and so on.  The time spent going between rows is a lot more than the time going between pixels on one row, so the effect is that _CopyBits is faster copying a short and wide section of a pixel map than it is copying a tall and narrow one.  To keep _CopyBits as fast as possible, copy the shortest rectangle possible.
  5508. Modifying the standard test again so that the source and destination rectangles are 256 pixels wide by 50 pixels tall produces a result of 110 ticks, while modifying it so that the source and destination rectangles are 50 pixels wide by 256 pixels tall results in a time of 123 ticks.  These 13 ticks may not seem like a big deal, but combined with other factors, there may be a case where they make a big difference.
  5509. Shape and Size of the Clip, Visible, and Mask Regions
  5510. _CopyBits always makes sure that it stays within the lines, so to speak.  _CopyBits copies pixels clipped to the maskRgn that you pass as the last parameter to the call.  If the destination is the current GrafPort, _CopyBits additionally clips to a region that’s the intersection of the clipRgn and visRgn of the port.  If the intersection of these three regions is not rectangular, then _CopyBits has to check each pixel to make sure it falls within the intersection, and this check slows _CopyBits down.  If the intersection of these three regions is rectangular, then _CopyBits takes the fast case of copying constant-sized rows.  To keep _CopyBits as fast as possible, make sure the intersection of the clipRgn and visRgn of the destination GrafPort and the maskRgn is rectangular.  Of course, if the destination GrafPort is a window, then the visRgn is under the user’s control.
  5511. In general, if the region that you are copying into has straight vertical edges for the most part, the time penalty of using a non-rectangular region is not that bad.  Regions that only have small portions that are straight and vertical are the ones that slow _CopyBits down in a big way.  Regions that are twisted or that have holes or islands can also have a big effect upon the speed, depending upon how complicated they are.  As a rule of thumb, if a region looks like it slows _CopyBits, it probably does.
  5512. Modifying the standard test so the maskRgn is set to a circle that inscribes the example pixel map results in a time of 303 ticks, which is considerably longer than the standard test result of 204 ticks that involved copying a much larger area.  Modifying the maskRgn to a square with 226 pixels per side, which has about the same total area of the circle just used, results in a time of 176 ticks.
  5513. Transfer Modes
  5514. Macintoshes without Color QuickDraw have eight transfer modes that work with _CopyBits, while those Macintoshes with Color QuickDraw get an additional nine modes.  Because the algorithms for each of these modes can be pretty different from the others, the time it takes _CopyBits to work with each of these modes can vary radically.  For several of these modes, the speed of _CopyBits can vary a lot depending upon the particular image being copied and the image over which this image is copied.  It can also vary non-linearly depending upon the depth of the pixel maps.  The arithmetic modes in particular are highly optimized for 32-bit deep pixel maps.
  5515. The standard test copies a fairly average-looking ray-traced image to a white background.  Modifying the standard test to erase the background between each of the 100 calls to _CopyBits produced the following results for the modes listed (the tests were obviously also changed to reflect the proper mode.  In addition, to make the results a little more meaningful, the time it took to erase the background has been subtracted from each result.
  5516. srcCopy    204    notSrcCopy    469    addOver    1500    adMax    1504
  5517. srcOr        436    notSrcOr    444    addPin    1514    adMin    1501
  5518. srcBic    441    notSrcBic    441    subOver    1493    blend    1553
  5519. srcXor    438    notSrcXor    436    subPin    1525    transparent    1107
  5520.                         hilite    3127
  5521. Of course, the amount of time taken by some of these modes can be changed by changing the image to copy and the image over which it is copied.  These figures are just to give an idea of how fast or slow some of these modes are in this particular situation.
  5522. There is actually one more mode which is not mentioned:  ditherCopy.  Apple introduced this mode with 32-Bit QuickDraw, and it makes _CopyBits do error-diffusion dithering when copying a pixel map from one depth to a pixel map of a lesser depth or to a pixel map of the same depth with a different color table.  The speed of this transfer mode can be very fast or very slow, depending upon what pixel depths and colors are used and the particular image being copied.  The ditherCopy mode is not included in the table since the range of figures is potentially very large; play with it and see for yourself.  For more information about this mode, refer to the Color QuickDraw chapter in Inside Macintosh, Volume VI and the 32-Bit QuickDraw Developers’ Notes from APDA.
  5523. Colorization
  5524. There is a variation of _CopyBits if the destination pixel map is the current port and the foreground color is not black or the background color is not white.  If this is the case, then the source image is colorized when it’s copied.  For details, see Technical Note #163, Adding Color with _CopyBits.  Because this colorization requires extra processing, _CopyBits slows down.  To keep _CopyBits as fast as possible, make sure the foreground color is black, the background color is white, and that the current GDevice pixel map’s color table has white in the first position and black in the last position.
  5525. Modifying the standard test so that the foreground color is pure red and the background color pure blue produces a result of 579 ticks.
  5526. Pixel Alignment
  5527. The alignment of pixels in the source pixel map relative to their alignment the destination pixel map can be surprisingly important to the speed of _CopyBits, but what is pixel alignment?  Following is an example to demonstrate the concept of pixel alignment.  Imagine you want to perform a _CopyBits on a one-bit-per-pixel off-screen pixel map into a window on a one-bit-per-pixel screen, and the window is three pixels from the left edge of the screen.
  5528. If you copy the entire off-screen pixel map to the left edge of the window, then _CopyBits must realign the pixels.  Since the leftmost pixels of the off-screen pixel map are on a byte boundary, but the left edge of the window is three pixels away from a byte boundary, _CopyBits has to shift (or realign) each byte from the off-screen pixel map by three pixels before placing it on the screen.  The process of aligning the pixels slows down _CopyBits.
  5529. Figure 1 shows an example of this realignment.  An off-screen bit map specified by a pointer to a BitMap called offScreen is being copied to a window specified by a WindowPtr called window.  window, which is 256 pixels wide and 256 pixels high, is positioned 50 pixels from the top of the screen and three pixels from the left edge of the screen.  The screen has 512 pixels horizontally and 342 pixels vertically.  The source rectangle that is passed to _CopyBits is sourceRect and the destination rectangle is destinationRect.  Because offScreen is misaligned by three pixels, _CopyBits has to shift offScreen by three pixels before placing the image on the screen.
  5530. Figure 1–offscreen Needs Realignment
  5531. By adjusting the off-screen pixel map so that its leftmost pixels are also three pixels away from a byte boundary, _CopyBits can just copy the bytes without shifting, which is a lot faster.  This example holds true on all Macintosh models, whether they have Color QuickDraw or not.  To keep _CopyBits as fast as possible, make sure the pixels in memory are aligned with the pixels on the screen.  Figure 2 shows the same situation as Figure 1, except that offScreen is now properly aligned to window.
  5532. Figure 2–offscreen Aligned
  5533. Many, if not most, Color QuickDraw Macintoshes have video cards that can display one pixel per byte, so one would think that pixel alignment does not apply in these cases, since all pixels are at byte boundaries.  This statement is true enough, but there is still another kind of alignment that should be done on these machines.  Macintoshes with Color QuickDraw generally have full 32-bit microprocessors, and these microprocessors are at their fastest when they can transfer long words aligned on long-word boundaries in memory.
  5534. Modifying the last example so that the off-screen pixel map and the screen are both eight-bits-per-pixel, the pixel at the extreme top left corner of the off-screen pixel map is located at a long-word boundary, because the Macintosh Memory Manager forces it to be located there; however, the pixel at the extreme top left corner of the window is located three bytes away from the previous long-word boundary.  No bit shifting is needed, because each pixel takes up a whole byte, but _CopyBits does have to take the non-optimum case of copying long words on non-long-word boundaries.  This case works fine, but it is not quite as fast as it could be.  To keep _CopyBits as fast as possible, make sure pixels in the source and destination pixel maps are aligned on long-word boundaries.
  5535. Since 1984, Macintosh programmers have been told that rowBytes must be even.  That is still true, but to allow _CopyBits to copy an entire pixel map on long-word boundaries, rowBytes must be a multiple of four so that every line in a pixel map begins on a long-word boundary.  The following formula can be used to find the minimum rowBytes needed for a pixel map’s bounds rectangle with right and left coordinates of bounds.right and bounds.left, and a pixel depth of pixelDepth:
  5536. rowBytes := ((pixelDepth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  5537. Off-screen GWorld support, which was introduced with 32-Bit QuickDraw, can automatically set up a pixel map so that it’s properly aligned to any part of the destination pixel map or bit map.  You can specify that you want this by passing zero for the pixel depth and passing the rectangle of the destination area in global coordinates.  See the 32-Bit QuickDraw Developers’ Notes and “Braving Offscreen Worlds” in d e v e l o p, January 1990 for details.
  5538. The way that _NewGWorld aligns a GWorld is to set up the off-screen pixel map so that its rowBytes is four bytes wider than one would normally calculate.  Four bytes is the maximum amount that any pixel map would have to be realigned at any pixel depth.  The bounds rectangle’s left coordinate is set to the negative of the left coordinate of the destination rectangle in global coordinates modulo (32 / pixel depth), because this is maximum amount that a pixel map must be shifted to achieve perfect alignment.  To build on the earlier example, assume you have a 128-pixel wide, eight-bit deep, off-screen pixel map to copy to a window that is three pixels away from the left edge of an eight-bit color screen.
  5539. First, the rowBytes for the off-screen pixel map is set to 131 to allow room for realignment.  To align the off-screen pixel map to the on-screen window, the left coordinate of the off-screen bit map’s bounds is set to -3 and the right coordinate is still at 128.  Notice that the off-screen pixel map’s bounds is now 131 pixels wide.  Now, the pixels in the off-screen pixel map with a horizontal coordinate of 0 are located three bytes away from the previous long-word boundary.  The pixels on the left edge of the window are also located three bytes away from the previous long-word boundary, so _CopyBits can copy long words on long-word boundaries.
  5540. If a user moves the window so that it’s two pixels from the left edge of the screen, the off-screen pixel map must be realigned.  _UpdateGWorld is used to do this.  It changes the left coordinate of the off-screen pixel map’s bounds rectangle to -2 and then it shifts all the pixels in the off-screen pixel map one pixel to the left.  The extra four bytes in each row provide the room for this shifting.  (Gives you some new respect for the off-screen support, doesn’t it?)
  5541. This same discussion applies to any pixel depth, though shallower pixel depths require bit shifting rather than byte shifting.  The same principles apply, though.  Notice that in a 32-bit deep pixel map, all pixels are aligned on long-word boundaries, so no bit shifting or byte shifting ever needs to be done on one of those.  _NewGWorld still adds four to rowBytes even in this case, however.
  5542. Modifying the standard test so that the source and destination pixel maps are four bits deep with perfect pixel alignment produces a result of 78 ticks; however, if the destination pixel map is one pixel left of perfect alignment, the result is 228 ticks.
  5543. Speed of the Hardware, Of Course
  5544. Obviously, the speed of the machine your application is running on affects the speed of _CopyBits.  To make _CopyBits as fast as possible, spend a lot of money.  However, there is more to the speed of _CopyBits than the speed of the Macintosh itself.  When the Macintosh 128K was released, there was only one place for pixel images: main memory.  Today, the situation is more complicated.  If you have a modular Macintosh, the pixel image for the screen is in the memory of a NuBus™ video card.  If you have a Macintosh IIci, you can optionally abandon the NuBus video card and use on-board video which takes up part of main memory.  If you have an 8•24 GC card with enough memory, the pixel images can be cached in the card’s memory along with the screen’s pixel image.
  5545. All of these different locations have different access speeds, and that can affect the speed of _CopyBits.  Additionally, different Macintoshes have different RAM access speeds.  The Macintosh II, IIx, IIcx, and SE/30 have faster RAM than the Macintosh Plus or SE.  The Macintosh IIci RAM access speed is faster still, and the Macintosh IIfx has faster RAM access than the IIci.  Different video cards have different access speeds.  The IIci has a cache card option which can vastly speed up on-board video RAM access speed.  Third-party video cards that work in the Processor Direct Slot of the Macintosh SE and SE/30 have their own speed characteristics as well.
  5546. There can also be a speed cost for crossing the different areas.  If _CopyBits copies between main memory and a NuBus video card, the image data has to be transferred across NuBus.  NuBus is a speed bottleneck, so copying an image across NuBus is slower than copying the image from one part of the screen to another or copying from one part of main memory to another.  Modifying the standard test to create two windows and two off-screen pixel maps—all eight bits deep with the standard color table then doing every combination of copying between off-screens, between windows, and between off-screens and windows produces the following results:
  5547.                 Off-screen to off-screen:    147
  5548.                 Screen to screen:         188
  5549.                 Off-screen to screen:        204
  5550.                 Screen to off-screen:        201
  5551. Performing the standard test on a Macintosh IIfx running System Software 6.0.5 with an Apple Extended Video Card yields a result of 153 ticks, which is not too shabby considering that the transfer is still going through NuBus.
  5552. Depth of Pixel Maps
  5553. This factor is pretty obvious and is sort of similar to the effect of the dimensions of the copied area:  the more bits per pixel there are in the pixel map to copy, the more memory that _CopyBits has to move and the longer it takes to get the job done, assuming that the source and destination pixel maps have the same depth.  To make _CopyBits as fast as possible, make sure the pixel maps are as shallow as possible.
  5554. If _CopyBits has to copy to a pixel map that has a different depth from the source pixel map, the relationship between speed and depth becomes more complicated.  There is a tradeoff between the time taken to change the depth of an image and the absolute amount of data that has to be processed.  Copying from a 1-bit deep pixel map to a 32-bit deep pixel map is not that slow because the amount of image data in the 1-bit deep pixel map is so small.
  5555. Modifying the standard test to transfer a four-bit deep pixel map to another four-bit deep pixel map produces a result of 78 ticks.
  5556. Color Mapping
  5557. Color QuickDraw expects a color table attached to every indexed pixel map.  Color tables specify what color each pixel value in the pixel map represents.  When an application calls _CopyBits to copy a pixel map into another pixel map, _CopyBits reproduces the colors of the image in the source pixel map as closely as possible—even if the colors available in the destination pixel map are different than those available in the source pixel map.  This reproduction is done through a process called “color mapping.”
  5558. When color mapping is done, the source pixel values are transformed into RGBColor records using the source pixel map’s color table.  These RGBColor records are passed to _Color2Index which finds the pixel values of the closest available colors in the current GDevice pixel map’s color table.  This same process is done when the source and destination pixel maps have differing depths.  The color table attached to the destination pixel map is not used in color mapping.  The colors available in the current GDevice pixel map’s color table are used instead.  So, the destination pixel map must have the same colors for the same pixel values as the current GDevice.  Otherwise, the resulting image in the destination pixel map gets the wrong colors.  See Inside Macintosh, Volume V-141, The Color Manager, for a description of _Color2Index.  It’s also helpful to read the “Inverse Tables” section in the same chapter on page V-137.
  5559. Now, if the source color table contains virtually the same colors for the same pixel values as the current GDevice pixel map’s color table, then any particular pixel value has the same color regardless of whether it is in the source or destination pixel map.  In this case, color mapping is a waste of time, because the pixels can be copied directly from the source pixel map to the destination pixel map without a loss of color fidelity.  _CopyBits takes advantage of this special case to yield some big speed improvements.  How is this special case detected?  Before this question is answered, it’s useful to understand how Color QuickDraw uses color tables.
  5560. The ctSeed Field
  5561. The first field in a color table is the ctSeed field.  This LongInt can be thought of as the color table’s version of the scrapCount field of the desk scrap.  Whenever an application calls _ZeroScrap, the desk scrap’s scrapCount is changed.  An application can tell that the desk scrap has changed by checking to see if the scrapCount has changed.  Similarly, whenever the contents of a color table are changed in any way, the ctSeed field should be changed to indicate to anyone using that color table that it has been modified.
  5562. Additionally, Color QuickDraw often uses the ctSeed as a fast check for color table equality.  If two color tables have the same ctSeed, then Color QuickDraw often assumes that their contents are equivalent.
  5563. After creating a new color table, an application has to get a valid value for the ctSeed field, and it can do so with the _GetCTSeed routine.  This routine generates a valid ctSeed value suitable for a new color table.  See Inside Macintosh, Volume V-143, The Color Manager, for a description of _GetCTSeed.
  5564. System Software 7.0 and 32-Bit QuickDraw each offer a routine called _CTabChanged which should be called after a color table is modified.  It takes a handle to the changed color table as a parameter.  If the _CTabChanged routine is not available, then the application should instead change ctSeed to a different valid value by calling _GetCTSeed and assigning the result to ctSeed, just like it’s done when the application creates a new color table.  You must use either one of these methods to tell Color QuickDraw that the color table has changed, or else the modified color table could be confused with the old color table, or with some other color table—this is especially critical if an 8•24 GC card is being used.  See the 32-Bit QuickDraw Developers’ Notes for details about the _CTabChanged routine.
  5565. The ctFlags Field
  5566. The ctFlags field is used as a set of flags that indicate some characteristics of the color table.  Currently, only the top two bits of ctFlags are of any interest to developers.  The most significant bit of ctFlags (bit 15) indicates whether the color table is a sequential color table or an indexed color table.  Bit 14 indicates that the color table is a special kind of sequential table if it is set.  In these kinds of color tables, the value fields indicate a palette entry in the destination window’s palette.  See the Palette Manager section of the 32-Bit QuickDraw Developers’ Notes for a discussion about this capability.
  5567. Sequential Color Tables
  5568. If bit 15 of ctFlags is set, the color table is a sequential color table.  Sequential color tables are usually found attached to GDevice pixel maps and to GWorld pixel maps.
  5569. In sequential color tables, the position of each color in the color table indicates the pixel value to which it corresponds.  For example, the fifth entry in a sequential color table always has a pixel value of four (pixel values start at zero).  The value field of each ColorSpec is not defined in sequential color tables, though they are used in color tables for screen GDevice records to indicate that a particular color is reserved, protected, or both.
  5570. Indexed Color Tables
  5571. If bit 15 and 14 of ctFlags are clear, the color table is an indexed color table.  In indexed color tables, the value field of each ColorSpec indicates the pixel value of the RGB in that ColorSpec.  For example, if the fifth ColorSpec in the color table has a value field containing 10, then that color has a pixel value of 10, not 4, as it would have been if this were a sequential color table.
  5572. Color Mapping or Non-Color Mapping
  5573. As noted before, _CopyBits can detect whether it has to do color mapping or not, so that it can take advantage of the speed benefits of no color mapping if possible.  How is this done?  First, _CopyBits checks to see if the ctSeed field of the source and destination color tables are the same and if the source and destination pixel maps have the same depths.  If both of these conditions are true, then _CopyBits assumes that the two color tables are identical and it just copies the pixels directly without color mapping.  If the ctSeed fields are different, _CopyBits checks manually through all of the colors in the source pixel map’s color table map to see if they map to the same pixel values in the current GDevice pixel map’s color table as they do in their own color table.  If they do, then _CopyBits again takes the fast case.
  5574. So to keep _CopyBits as fast as possible, make sure that the source and destination color tables have virtually the same colors for the same pixel values.  This applies even if one color table is an indexed color table and the other is a sequential color table, or if the source and destination color tables are both indexed but the order of the ColorSpec records differ.
  5575. Modifying the standard test so that the source pixel map has a color table that is the reverse of the standard eight-bit system color table (the grays have low pixel values and the light pinks and yellows have high pixel values) and the destination pixel map has the standard eight-bit system color table produces a result of 470 ticks.
  5576. By the way, color tables do not make any sense for direct pixel maps, so this discussion does not apply to them.  Direct pixel maps do have a color table attached to them, but they’re just there so that an application that assumes that a color table is attached does not bomb.
  5577. Scaling
  5578. If the source and destination rectangles are the same size, _CopyBits has the fairly easy task of just transferring the pixels from the source pixel map to the destination pixel map; however, if the source and destination rectangles are different sizes, _CopyBits has to scale the copied image, which slows it down a lot.  To keep _CopyBits as fast as possible, make sure the source and destination rectangles have the exact same dimensions.
  5579. Modifying the standard test to copy a 128 by 128 pixel portion of the source pixel map to the whole 256 by 256 pixel window produces a result of 1,159 ticks.
  5580. Of Time and Space
  5581. Hopefully, this Note makes it a lot clearer to you how to set up a situation in which your _CopyBits calls are as fast as your situation allows.  It’s important to realize that this Note does not cover every single factor that has an influence on the speed of _CopyBits.  There are many more factors which are just too unpredictable.  For example, _CopyBits is highly optimized for many special cases, and those optimizations can have a big effect on the speed of the copy.  Also, the speed of _CopyBits can be affected by interrupt-level tasks.  It’s up to you to fine tune your programs to your particular situations.
  5582. Further Reference:
  5583. •    Inside Macintosh, Volume I, QuickDraw
  5584. •    Inside Macintosh, Volume V, The Color Manager
  5585. •    Inside Macintosh, Volume VI, Color QuickDraw
  5586. •    Technical Note M.IM.ColorCopyBits, Adding Color With _CopyBits
  5587. •    d e v e l o p, January 1990, “Realistic Color for Real-World Applications”
  5588. •    d e v e l o p, January 1990, “Braving Offscreen GWorlds”
  5589. •    32-Bit QuickDraw Developers’ Notes (APDA)
  5590. NuBus is a trademark of Texas Instruments
  5591. ‚◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  5592. /ZÅ#
  5593.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5594. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5595. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5596. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5597. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5598.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5599. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  5600. IR.°dONLNd{<éë(®Z'32-Bit QuickDraw:  Version 1.2 Features
  5601. °dONLNd(ç<úr*Imaging°dONLNd0çöú˛(∏∏ M.IM.32BitQD
  5602. °dONLNd=®<¥q(–Z Written by:°dONLNdI®Ñ¥Œ)HGuillermo Ortiz°dONLNdY®À¥˛(–È
  5603. April 1990°dONLNdd¿<ÃÁ(ËZOThis Technical Note describes the changes and enhancements to 32-Bit QuickDraw °dONLNd≥¿ÁÃ˛(Ëfrom°dONLNd∏Ã<ÿb(ÙZversion °dONLNd¿Ãbÿ˛)&S1.0 (as shipped on the original Color Disk) to version 1.2, which ships with System°dONLNdÿ<‰R(Z9Software 6.0.5 and later.  This Note assumes familiarity °dONLNdMÿR‰l(pwith °dONLNdRÿl‰ø)Inside Macintosh°dONLNdbÿø‰˛)S , Volume V,°dONLNdn‰<E( Z4Color QuickDraw, and 32-Bit QuickDraw release notes. X
  5604. °dONLNd£<$∂*432-Bit QuickDraw
  5605. °dONLNd¥0<<®*GVersion 1.0 of 32-Bit QuickDraw shipped in May 1989 in response to the °dONLNd˚0®<˛(XΔgrowing need for°dONLNd <<HZ(dZColor °dONLNd<ZH˛)TQuickDraw support for direct color devices and pictures (PICT2) and video boards for°dONLNdgH<Ty(pZ
  5606. large-screen °dONLNdtHyT˛)=Mmonitors which require 32-bit addressing for black and white operation.  This°dONLNd¬T<`(|Z]original version of 32-Bit QuickDraw was a separate file that had to be copied manually into °dONLNdT`˛(|the°dONLNd#`<l(àZ-System Folder.  With the introduction of the °dONLNdP`l˛)‘/Macintosh IIci, Apple put 32-Bit QuickDraw into°dONLNdÄl<xÃ(îZPROM.  Now System Software 6.0.5 and later offer 32-Bit QuickDraw as an integral °dONLNd–lÃx˛(îÍ part of the°dONLNd‹x<ÑÉ(†ZASystem Software which can be installed by the standard Installer °dONLNdxÉÑ˛(†°(although the file is still°dONLNd9Ñ<êj(¨Z
  5607. separate).°dONLNdDú<®n*
  5608. This Note °dONLNdNún®˛)2Ndescribes the changes and enhancements in version 1.2 of 32-Bit QuickDraw from°dONLNdù®<¥Õ(–Zversion 1.0.  Beginning with °dONLNd∫®Õ¥˛)ë>version 1.2, QuickDraw functionality is identical on all Color°dONLNd˘¥<¿ˆ(‹Z&QuickDraw machines, including all the °dONLNd¥ˆ¿˛)∫3performance improvements which were originally only°dONLNdS¿<Ã∂(ËZavailable in the IIci ROM.
  5609. °dONLNdn‰<ÛB*'%New Features (In No Particular Order)
  5610. °dONLNdîˇ< *#PICTs Contain Font Name Information°dONLNd∏<$*&Every time you draw text inside of an ,
  5611. Courier°dONLNdfi#d)‘ _OpenPicture°dONLNdÍd$Ö)T and °dONLNdÔÖ#‡)!
  5612. _ClosePicture°dONLNd¸‡$˛)[ pair,°dONLNd$<0E(LZ7QuickDraw stores the name of the current font and uses °dONLNd:$E0˛(Lc&it when playing back the picture.  The°dONLNda0<<ë(XZIopcode used to save this information is $002C and its data is as follows:
  5613.     °dONLNd´H<Sπ*    PictFontInfo = Record°dONLNd≈R<]ü*
  5614. G                     length   : Integer;    { length of data in bytes }°dONLNd
  5615. \<gü*
  5616. G                     fontID   : Integer;    { ID in the source system }°dONLNdUf<qˇ*
  5617. '                     fontName : Str255;°dONLNd}p<{Ø*
  5618.                    END;
  5619. °dONLNdïÜ<íΔ*QuickDraw only saves this °dONLNdØÜΔí˛)ä;information one time for each font used in a picture.  When°dONLNdÎì<ü‚(ªZ#QuickDraw plays back a picture, it °dONLNdì‚ü
  5620. )¶    uses the °dONLNdí
  5621. û7)+fontID°dONLNdì7ü˛)*+ as a reference into the list of font names°dONLNdIü<´N(«Z<which are used to set the correct font on the target system. ◊X◊
  5622. *%'32-Bit QuickDraw:  Version 1.2 Features(Ï1) of 5ˇ°¿Ù%%DSIDICT:_cv
  5623. currentdict /bu known {bu}if
  5624. userdict /_cv known not{userdict /_cv 30 dict put}if
  5625. _cv begin
  5626. /bdf{bind def}bind def
  5627. currentscreen/cs exch def/ca exch def/cf exch def
  5628. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5629. /ss{//cf //ca //cs setscreen}bdf
  5630. /stg{ss setgray}bdf
  5631. /strgb{ss setrgbcolor}bdf
  5632. /stcmyk{ss cvcmyk}bdf
  5633. /min1{dup 0 eq{pop 1}if}bdf
  5634. end
  5635. currentdict /bn known {bn}if
  5636. †ø¬◊#ˇ ˇˇˇˇ#◊ 
  5637. IR,Times
  5638. .+6-Macintosh Technical Notes /4/˘
  5639. °dONLNd)5µ*$ For example, the following code:,
  5640. Courier
  5641.     °dONLNd!ALv*F    GetFNum('Venice', theFontID);    { Set a font before opening PICT}°dONLNdhKVê*
  5642.     TextFont(theFontID);°dONLNdÅ_j—*%    pHand2 := OpenPicture (pictRect);°dONLNdßitÜ*
  5643.         MoveTo(20,20);°dONLNdæs~‡*
  5644. (        DrawString(' Better be Venice');°dONLNdÁáí—*%        GetFNum('Geneva', theFontID);°dONLNd
  5645. ëú§*
  5646.         TextFont(theFontID);°dONLNd*õ¶Ü*
  5647.         MoveTo(20,40);°dONLNdA•∞©*
  5648.         DrawString('Geneva');°dONLNd_πƒ€*'        GetFNum('New York', theFontID);°dONLNdá√Œ§*
  5649.         TextFont(theFontID);°dONLNd§ÕÿÜ*
  5650.         MoveTo(20,60);°dONLNdª◊‚≥*
  5651.         DrawString('New York');°dONLNd€Îˆ—*%        GetFNum('Geneva', theFontID);°dONLNdı§*
  5652.         TextFont(theFontID);°dONLNdˇ
  5653. Ü*
  5654.         MoveTo(20,80);°dONLNd5    ©*
  5655.         DrawString('Geneva');°dONLNdSm*
  5656.     ClosePicture;
  5657. °dONLNdf)5*:generates a picture containing font information like this:
  5658.     °dONLNd°ALÅ*    OpCode 0x002C {9,°dONLNd∏KVä*
  5659. J        "0005 0656 656E 6963 65"}              /* save current font     */°dONLNdU`w*
  5660.     TxFont 'venice'°dONLNd_jÍ*
  5661. *    DHDVText {20, 20, " Better be Venice"}°dONLNdBitä*
  5662. J    OpCode 0x002C {9,                          /* save next font name   */°dONLNdçs~Ω*
  5663. !        "0003 0647 656E 6576 61"}°dONLNdØ}àw*
  5664.     TxFont 'geneva'°dONLNd√áíï*
  5665.     DVText {20, "Geneva"}°dONLNd›ëúä*
  5666. J    OpCode 0x002C {11,                         /* ditto                 */°dONLNd(õ¶÷*
  5667. &        "0002 084E 6577 2059 6F72 6B"}°dONLNdO•∞|*
  5668.     TxFont 'newYork'°dONLNddØ∫ü*
  5669.     DVText {20, "New York"}°dONLNdÄπƒÄ*
  5670. H    TxFont 'geneva'                            /* second Geneva does not°dONLNd…√Œä*
  5671. J                                                 need another $002C guy */°dONLNdÕÿï*
  5672.     DVText {20, "Geneva"}
  5673. °dONLNd.„Ô•*VThis feature works regardless of the type of picture being saved, including old style °dONLNdÑ„•Ô⁄( √
  5674. PICTs in a°dONLNdè¸¥(6black and white port.  Using °dONLNd¨Ô¥˚)ú
  5675. _OpenCPicture°dONLNdπ¸O)[  instead of °dONLNd≈ÔO˚£)@ _OpenPicture°dONLNd—£¸⁄)T  to start a°dONLNd›¸($64recording session results in the same functionality.°dONLNd ˛*&Direct PixPat Structures Now Supported°dONLNd9-9*3QuickDraw now supports 16-bit and 32-bit per pixel °dONLNdl,8=)˚PixPat°dONLNdr-=9u)*
  5676.  structures (°dONLNd,u8¬)8 patType = 1°dONLNdä-¬9–)M).  °dONLNdé-–9⁄)In°dONLNdë:F±(b6 addition, it now supports a new °dONLNd±9±E‚)ôpatType°dONLNd∏:‚Fˆ)1 (3) °dONLNdΩ:ˆF⁄).which uses dithering whenever 16-bit or 32-bit°dONLNdÌFR˘(n60pixel patterns are displayed on indexed devices.°dONLNd^j˙*%Direct 'cicn' Resources Now Supported°dONLNdDwÉ*3QuickDraw now supports 16-bit and 32-bit per pixel °dONLNdwvÇ=)˚'cicn'°dONLNd}w=É⁄)*! resources.  The 16-bit per pixel°dONLNdüÑêJ(¨6Dis particularly cool since you save the space required for an 8-bit °dONLNd„ÉJèt(¨h'clut'°dONLNdÈÑtêx)*. ◊4◊˘
  5677. (Ï62) of 5(ÏS'32-Bit QuickDraw:  Version 1.2 Featuresˇ(◊#ˇ ˇˇˇˇ#◊ 
  5678. IR,Times
  5679. .+Z-Developer Support Center(-
  5680. April 1990 /X/
  5681. °dONLNd)<5Ω(QZ<GWorlds Can Now Be Allocated in MultiFinder Temporary Memory°dONLNd=B<NS*You °dONLNdABSNæ)can now use the new ,
  5682. Courier°dONLNdUAæM)k
  5683. useMFTempBit °dONLNdbBNs)\(bit 2) in a call to °dONLNdwAsM≤)Y    NewGWorld°dONLNdÄB≤N˛)? as an option to°dONLNdëN<Z/(vZ1allocate pixels in MultiFinder temporary memory. °dONLNd¬N/Z˛)Û) In addition, you can now allocate screen°dONLNdÏZ<f˛(ÇZ]buffers in MultiFinder temporary memory using the following routine, defined in Pascal and C:
  5684.     °dONLNdJr<}ã*CFUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN;°dONLNdé|<á,*
  5685. 0                              VAR gdh: GDHandle;°dONLNdøÜ<ë©*
  5686. I                               VAR offscreenPixMap: PixMapHandle): QDErr;°dONLNd    ê<õê*
  5687. D             INLINE $203C,$000E, $0015,$AB1D; { Move.L #$000E0015,D0°dONLNdNö<•c*
  5688. ;                                               _QDOffscreen°dONLNdä§<Ø"*
  5689. .                                             }°dONLNdπ∏<√ö*Fpascal QDErr NewTempScreenBuffer (Rect *globalRect, BOOLEAN purgeable,°dONLNd¬<Õ*
  5690. ,                              GDHandle *gdh,°dONLNd-Ã<◊h*
  5691. <                              PixMapHandle *offscreenPixMap)°dONLNdj÷<·*
  5692. ,             ={0x203C,0x000E,0x0015,0xAB1D};
  5693. °dONLNdòÏ<¯‚*Indexed to Indexed Dithering°dONLNdµ<{*    _CopyBits°dONLNdæ{ñ)? now °dONLNd√ñ’)
  5694. supports the °dONLNd–’)?
  5695. ditherCopy°dONLNd⁄˛)F. transfer mode whenever the destination device°dONLNd    <7(9Z7is between one and eight bits per pixel, regardless of °dONLNd@7˛)˚)the depth of the source image.  With this°dONLNdj<)ä(EZFsupport, an eight-bit image can now be approximated on a one-bit or a °dONLNd∞ä)˛(E®four-bit device by using°dONLNd…)<5Õ(QZXerror diffusion.  Furthermore, an eight-bit image could also be dithered to a different °dONLNd!)Õ5˛(QÎ
  5696. set of 256°dONLNd,5<Aù(]ZNcolors or a four-bit image could be dithered to an eight-bit device that does °dONLNdz5ùA˛(]ªnot have the desired°dONLNdèA<M](iZcolors.°dONLNdóY<e *"32-Bit Addressed PixMap Structures°dONLNd∫r<~§*Version 1.2 defines a °dONLNd–r§~º)hnew °dONLNd‘qº}˚)    pmVersion°dONLNd›r˚~)? (°dONLNdflq}g)baseAddr32 = 4°dONLNdÌrg~Δ)d) for 32-bit pointer °dONLNdqΔ}˛)_baseAddr°dONLNd <ã(ßZ
  5697. values.  The °dONLNd~ä∑)CbaseAddr°dONLNd ∑ãÊ)8     of such °dONLNd)~Êä)/PixMap°dONLNd/ã≥)*# structures is treated as a 32-bit °dONLNdR≥ã˛)£address, so no°dONLNdaã<óú(≥ZJstripping or address translation is performed on it in 32-bit mode.  This °dONLNd´ãúó˛(≥∫is a specially useful°dONLNd¡ò<§Ë(¿Z#feature when the base address of a °dONLNd‰óË£)¨PixMap°dONLNdÍò§)* °dONLNdÎò§r)points to a NuBus
  5698.     °dONLNd¸ñr°z(Ωê™
  5699. °dONLNd˝òz§˛+ address, for example in a°dONLNd§<∞ü(ÃZvideo grabber board.°dONLNd-Ω<…x* A new call, °dONLNd9ºx»≈)< Pixmap32Bit°dONLNdDΩ≈…)M, is now available °dONLNdWΩ…à)Zto inquire if a given °dONLNdmºà»≤)iPixMap°dONLNdsΩ≤…˛)* requires 32-bit°dONLNdÑ…<’s(ÒZ addressing.
  5700.     °dONLNdê·<Ï'*/FUNCTION Pixmap32Bit(pmh:pixMapHandle):Boolean;°dONLNd¿Î<ˆc*
  5701. ;    INLINE $203C,$0004, $0016,$AB1D; { Move.L #$00040016,D0°dONLNd¸ı<6*
  5702. 2                                      _QDOffscreen°dONLNd/ˇ<
  5703. ı*
  5704. %                                    }°dONLNdU<*,pascal BOOLEAN Pixmap32Bit(pixMapHandle pmh)°dONLNdÇ<(ı*
  5705. %    = {0x203C,0x0004, 0x0016,0xAB1D};
  5706. °dONLNd©3<?fl*Updated GetPixBaseAddress°dONLNd√L<X§*Version 1.2 updates °dONLNd◊K§W)hGetPixBaseAddress°dONLNdËLXã)w to return the address °dONLNdˇLãX≤)pof any °dONLNd    K≤W‹)'PixMap°dONLNd     L‹X˛)*.  The°dONLNd    Y<ek(ÅZ@routine does the right address translation or stripping for all °dONLNd    SXkdï(ÅâPixMap°dONLNd    YYïeö)* °dONLNd    ZYöe˛)structures, including°dONLNd    pf<rá(éZscreen devices, °dONLNd    ÄfárR)K'unlocked GWorlds, and 32-bit addressed °dONLNd    ßeRq|)ÀPixMap°dONLNd    ≠f|r˛)* structures.  The address it°dONLNd     s<k(õZ returns is °dONLNd    ’sks)/6only valid in 32-bit addressing mode. Also unless the °dONLNd
  5707. rs~ù(õëPixMap°dONLNd
  5708. sù˛)* is locked and made°dONLNd
  5709. %Ä<åÛ(®Z%unpurgeable, the address returned by °dONLNd
  5710. JÛãj)∑GetPixBaseAddress°dONLNd
  5711. [Äjåz)w is °dONLNd
  5712. _Äzå˛)only valid until any call to°dONLNd
  5713. |å<ò‚(¥Z!QuickDraw or the toolbox is made. ◊X◊
  5714. *8'32-Bit QuickDraw:  Version 1.2 Features(Ï3) of 5ˇJ◊#ˇ ˇˇˇˇ#◊ 
  5715. IR,Times
  5716. .+6-Macintosh Technical Notes /4/˘
  5717. °dONLNd)Õ*_CopyBits from Screen Devices°dONLNd6B*4The picture recording mechanism has changed so that °dONLNdR6BL)ˇ if you call ,
  5718. Courier°dONLNd^5LAã)5    _CopyBits°dONLNdg6ãB⁄)? while recording°dONLNdxCOé(k6a picture with the source °dONLNdíBéN∏)vPixMap°dONLNdòC∏O‡)*     being a °dONLNd°C‡O⁄)(5screen device, the data is correctly accumulated into°dONLNd◊P\*(x6>the picture.  Note that if the screen being copied is not the °dONLNdP*\ï(xHmain screen, then the °dONLNd+Oï[ø)kPixMap°dONLNd1Pø\⁄)* must°dONLNd7]i(Ö6be a 32-bit addressed °dONLNdM\h©)gPixMap°dONLNdS]©i∞)*. °dONLNdU]∞i⁄)@ No auxiliary screen buffer is allocated if the source rectangle°dONLNdñiuà(ë6covers only one screen.°dONLNdÆÅç∫*New Picture Recording Trap°dONLNd…ö¶x*Version 1.2 adds a °dONLNd‹öx¶™)`
  5719. new call, °dONLNdÊô™•)2
  5720. _OpenCPicture°dONLNdÛö¶⁄)[-, to create pictures that contain information°dONLNd!¶≤Ù(Œ60regarding the native resolution of the recorded °dONLNdQ¶Ù≤⁄)‹-image.  When QuickDraw draws this picture, it°dONLNd≤æ†(⁄6Qscales the image to the resolution of the target device.  Applications that need °dONLNd–≤†æ⁄(⁄æ to scale the°dONLNd›æ ˚(Ê61images directly can also access this information.
  5721.     °dONLNd÷·?*;FUNCTION OpenCPicture(VAR CPictInfo:CPictRecord):PicHandle;°dONLNdK‡Îm*
  5722.     INLINE $AA20;°dONLNd]Ùˇ!*5pascal PicHandle OpenCPicture(CPictRecord *CPictInfo)°dONLNdì˛    ^*
  5723.     =  0xAA20;
  5724. °dONLNd¢ 5*where
  5725.     °dONLNd®,7|*struct CPictRecord {°dONLNdΩ6A∑*
  5726. S      Rect CPicFrame;           /* Bounding rect of Picture at native resolution */°dONLNd@K∑*
  5727. S      Fixed CPicHRes;           /* native horizontal resolution in pixels/inch   */°dONLNdeJU∑*
  5728. S      Fixed CPicVRes;           /* native vertical resolution in pixels/inch     */°dONLNdπT_∑*
  5729. S      short CPicVersion;        /* version of this PICT info set to -2           */°dONLNd
  5730. ^i∑*
  5731. S      short reserved;           /* for future expansion set to zero              */°dONLNdahs∑*
  5732. S      long reserved;            /* for future expansion set to zero              */°dONLNdµr}J*
  5733.  
  5734.         };
  5735. °dONLNd¿àî*5The new picture header data looks like the following:°dONLNdˆ†`¨©+H
  5736. Size in bytes°dONLNd†√¨„)cName°dONLNd    †/¨p)l Description À|Àµ°dONLNdÆ∫Ö(÷ù2°dONLNd≠√πÙ)DpicSize°dONLNd Æ∫ê)Zlow word of picture size°dONLNd:ª«Ö(„ù8°dONLNd<∫√Δ˚)DpicFrame°dONLNdEª«ã)Zbounding box at 72 dpi Ê|ʵ°dONLNd\‡<Ïê(ZPicture Header  X √°dONLNdkÓ<˙B*2°dONLNdmÌi˘Ø)-
  5737. version op°dONLNdxÓÃ˙?)cversion opcode = $0011°dONLNdè˚<B(#Z2°dONLNdë˙iö)-version°dONLNdô˚ÃC)cversion number = $02FF°dONLNd∞<B(0Z2°dONLNd≤i®)-    Header op°dONLNdºÃ@)cheader opcode  = $0C00°dONLNd”<!B(=Z2°dONLNd’i ö)-version°dONLNd›Ã!H)c-2 for PICTs created with °dONLNd˜H £)|
  5738. _OpenCPicture°dONLNd"<.B(JZ2°dONLNd!i-°)-reserved°dONLNd/<;B(WZ4°dONLNd.i:Ö)-HRes°dONLNd/Ã;S)cnative horizontal resolution (°dONLNd5.S:v)áFixed°dONLNd:/v;z)#)°dONLNd<<<HB(dZ4°dONLNd>;iGÖ)-VRes°dONLNdC<ÃHF)cnative vertical resolution (°dONLNd_;FGi)zFixed°dONLNdd<iHm)#)°dONLNdfI<UB(qZ8°dONLNdhHiTö)-SrcRect°dONLNdpIÃU7)cnative source rectangle°dONLNdàV<bB(~Z4°dONLNdäUia°)-reserved ÅXÅ√ ◊4◊˘
  5739. (Ï64) of 5(ÏS'32-Bit QuickDraw:  Version 1.2 FeaturesˇF◊#ˇ ˇˇˇˇ#◊ 
  5740. IR,Times
  5741. .+Z-Developer Support Center(-
  5742. April 1990 /X/
  5743. °dONLNd*<6(RZ,The following is a sample PICT created with ,
  5744. Courier°dONLNd,)5m)÷
  5745. _OpenCPicture°dONLNd9*m6p)[:
  5746.     °dONLNd;B<Mö(iZF    00 48                          /* low word of size              */°dONLNdÇL<Wö*
  5747. F    00 00 00 00 00 7D 00 7D        /* picFrame at 72 dpi            */°dONLNd…V<aö*
  5748. F    00 11                          /* PICT version opcode           */°dONLNd`<kö*
  5749. F    02 FF                          /* version number                */°dONLNdWj<uö*
  5750. F    0C 00                          /* PICT header Opcode            */°dONLNdût<ö*
  5751. F    FF FE                          /* PICT version -2               */°dONLNdÂ~<âö*
  5752. F    00 00                          /* reserved                      */°dONLNd,à<ìö*
  5753. F    01 20 00 00                    /* HRes (Fixed)                  */°dONLNdsí<ùö*
  5754. F    01 20 00 00                    /* VRes (Fixed)                  */°dONLNd∫ú<ßö*
  5755. F    00 00 00 00 01 F4 01 F4        /* picFrame at native resolution */°dONLNd¶<±ö*
  5756. F    00 00 00 00                    /* reserved                      */°dONLNdH∞<ªö*
  5757. F    /* picture data follows                                         */°dONLNdè∫<≈ö*
  5758. F    00 FF                          /* end of picture opcode         */
  5759. °dONLNd÷‹<Îõ*& Random Notes
  5760. °dONLNd„˜<‡* For information on bug fixes in °dONLNd˜‡˛)§5the System Software 6.0.5 release of 32-Bit QuickDraw°dONLNd9<≈(+ZR(version 1.2), please refer to the System Software 6.0.5 Change History, which is °dONLNdã≈˛(+„ available on°dONLNdò<(7Z&the Developer CD Series, AppleLink in °dONLNdæ˛)»0the Developer Services Bulletin Board (Developer°dONLNdÔ<'û(CZServices: Macintosh °dONLNdû'˛)bEDeveloper Technical Support: System Software), and the Apple FTP site°dONLNdI'<3(OZ/on the Internet in the ~ftp/pub/dts/sw.license.°dONLNdy@<L*,Note that the dispatching mechanism for the °dONLNd•@L.)Ÿnew °dONLNd©?.KÇ) _QDOffscreen°dONLNdµ@ÇL˛)T calls is slightly different°dONLNd“M<YË(uZ#than previously documented; it now °dONLNdıMËY†)¨&requires that the high word passed in °dONLNdL†XÆ)∏D0°dONLNdMÆY˛) contain the total°dONLNd0Y<e¸(ÅZ*length of the parameters (in bytes).  The °dONLNdZY¸e˛)¿8reason for this change is that if the call is made in an°dONLNdìe<qV(çZ:earlier version of 32-Bit QuickDraw, the system can strip °dONLNdÕeVq˛(çt!the parameters from the stack and°dONLNdÔr<~[(öZreturn °dONLNdˆq[}å)QDError°dONLNd˝rå~=)1) set to the caller (instead of crashing).°dONLNd'ñ<¢¶(æZFurther Reference: ¡X¡°dONLNd:£NØR+
  5761. •°dONLNd<£`ر)Inside Macintosh°dONLNdL£±ØC)Q, Volume V, Color QuickDraw°dONLNdhØNªR(◊l•°dONLNdjØ`ªm)432-Bit QuickDraw Release Notes (available from APDA)°dONLNdüªN«R(„l•°dONLNd°ª`«)$System Software 6.0.5 Change History°dONLNdΔ«N”R(Ôl•°dONLNd»«`”ó)
  5762. d e v e l o p°dONLNd’«ó”æ)7    , Issue I°dONLNdflfl<Î(Z*NuBus is a trademark of Texas Instruments. ◊X◊
  5763. *Â'32-Bit QuickDraw:  Version 1.2 Features(Ï5) of 5ˇ◊#ˇ ˇˇˇˇ#◊†Ç 
  5764. /ZÅ#
  5765.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5766. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5767. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5768. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5769. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5770.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5771. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  5772. IR.°dONLNdz<ç(ßZBasic QuickDraw Q&As
  5773. °dONLNdå<õr*Imaging°dONLNdånõ˛(∑åM.IM.BasicQD.Q&As
  5774. °dONLNd/ß<≥t(œZ Revised by:°dONLNd;ßÑ≥ˇ)HDeveloper Support Center°dONLNdTßæ≥˛(œ‹ October 1992°dONLNda≥<øq(€Z Written by:°dONLNdm≥Ñøˇ)HDeveloper Support Center°dONLNdÜ≥æø˛(€‹ October 1990°dONLNdìÀ<◊⁄(ÛZThis Technical Note contains a °dONLNd≤À⁄◊˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÏ◊<„†(ˇZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd3◊†„˛(ˇæthe DSC engineers.°dONLNdF„<Ôu( Z
  5775. While DSC °dONLNdP„uÔ˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdùÔ<˚q(Z don’t have °dONLNd®Ôq˚˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˙˚<Ÿ(#Znew technical information and °dONLNd˚Ÿ˛)ù6updates to you quickly, saving the polish for when the°dONLNdO<(/Z,information migrates into reference manuals.°dONLNd|<+k*:Q&As are now included with Technical Notes to make access °dONLNd∂k+˛(Gâto technical updates easier for°dONLNd÷+<7.(SZ/you. If you have comments or suggestions about °dONLNd+.7˛)Ú*Q&A content or distribution, please let us°dONLNd07<C\(_Zknow °dONLNd57\C˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNdC<Oi(kZ9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdπ[<g«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."z  íXí
  5776. °dONLNdå<õ†*42Sending PostScript via PostScriptHandle PicComment
  5777. °dONLNd;õ<ßb* Written:°dONLNdDõàß¶)L5/1/90°dONLNdKß<≥Å(œZLast reviewed:°dONLNdZßà≥¨)L10/9/91°dONLNdbø<ÀG(ÁZIf °dONLNdeøGÀ˛) XI use the PostScriptHandle PicComment to send PostScript code to the LaserWriter driver,°dONLNdæÀ<◊£(ÛZHdo I need to open a picture and then draw the picture to the driver, or °dONLNdÀ£◊˛(Û¡can I just use the°dONLNd◊<„õ(ˇZHPicComment with no picture open while drawing to the printer’s grafPort?°dONLNdb„<ÔN* ___°dONLNdf˚<ò*You don’t need to °dONLNdx˚ò˛)\Gcreate a picture with your PicComment in it and draw the picture to the°dONLNd¿<(/ZQdriver. The best method for sending PostScript code to the LaserWriter is to use °dONLNd˛(/the°dONLNd<_(;Z8PostScriptHandle PicComment documented in the Macintosh °dONLNdM_˛(;}Technical Note #91, “Optimizing°dONLNdm<+V(GZ6for the LaserWriter—Picture Comments,” as shown below.,
  5778. Courier
  5779.     °dONLNd§7<Bá*PrOpenPage(...)°dONLNd¥A<Lc*
  5780. ;{ Send some QuickDraw so that the Printing Manager gets a }°dONLNdK<V    *
  5781. ){ chance to define the clipping region. }°dONLNdU<`}*
  5782.  
  5783. PenSize(0,0);°dONLNd)_<jx*
  5784. MoveTo(0,0);°dONLNd6i<tx*
  5785. LineTo(0,0);°dONLNdDs<~}*
  5786.  
  5787. PenSize(1,1);°dONLNdS}<à*
  5788. $PicComment(PostScriptBegin, 0, NIL);°dONLNdxá<í*
  5789. ({ QuickDraw representation of graphic. }°dONLNd°ë<úë*
  5790. MoveTo(100, 100);°dONLNd≥õ<¶ë*
  5791. LineTo(200, 200); ◊X◊
  5792. **Basic QuickDraw Q&As(Ïˇ1) of 22ˇ°¿Ù%%DSIDICT:_cv
  5793. currentdict /bu known {bu}if
  5794. userdict /_cv known not{userdict /_cv 30 dict put}if
  5795. _cv begin
  5796. /bdf{bind def}bind def
  5797. currentscreen/cs exch def/ca exch def/cf exch def
  5798. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5799. /ss{//cf //ca //cs setscreen}bdf
  5800. /stg{ss setgray}bdf
  5801. /strgb{ss setrgbcolor}bdf
  5802. /stcmyk{ss cvcmyk}bdf
  5803. /min1{dup 0 eq{pop 1}if}bdf
  5804. end
  5805. currentdict /bn known {bn}if
  5806. †ø*◊#ˇ ˇˇˇˇ#◊ 
  5807. IR,Times
  5808. .+6-Macintosh Technical Notes /4/˘,
  5809. Courier
  5810.     °dONLNd(Â*){ PostScript representation of graphic. }°dONLNd*'20*
  5811. 8thePSHandle^^ := '100 100 moveto 200 200 lineto stroke';°dONLNdc1<0*
  5812. 8PicComment(PostScriptHandle, GetHandleSize(thePSHandle),°dONLNdú;Fö*
  5813.               thePSHandl);°dONLNd∑EP¬*
  5814. "PicComment(PostScriptEnd, 0, NIL);°dONLNd⁄OZh*
  5815. PrClosePage(...)
  5816. °dONLNdÎeqC*5The above code prints a line on any type of printer, °dONLNd eCq⁄(çaPostScript or not. The first°dONLNd=q}fi(ô6&MoveTo/LineTo combination is required °dONLNdcqfi}⁄)Δ3to give the LaserWriter driver a chance to define a°dONLNdó}âA(•6    clipping °dONLNd†}Aâ⁄))Uregion. The LaserWriter driver replaces the grafProcs record in the grafPort returned°dONLNdˆâï}(±6Kfrom PrOpenDoc. In order for the LaserWriter driver to get execution time, °dONLNdAâ}ï⁄(±õyou must execute a°dONLNdTï°z(Ω6IQuickDraw drawing routine that calls one of the grafProcs. In this case, °dONLNdùïz°⁄(Ωòthe MoveTo/LineTo°dONLNdذ≠ç(…6Ocombination calls the StdLine grafProc. When StdLine executes, it notices that °dONLNd˛°ç≠⁄(…´the grafPort has°dONLNd≠πÃ(’6Vbeen reinitialized, and therefore initializes the clipping region for the port. Until °dONLNde≠Ãπ⁄(’Íthe°dONLNdiπ≈](·6CMoveTo/LineTo combination is executed, the clipping region for the °dONLNd¨π]≈⁄(·{port is set to (0,0,0,0). If°dONLNd…≈—è(Ì6MPostScript code is sent via the PostScriptHandle PicComment before executing °dONLNd≈è—⁄(Ì≠
  5817. any QuickDraw°dONLNd$—›?(˘6Aroutines, all PostScript operations will be clipped to (0,0,0,0).°dONLNdfÈı≠*The next thing that’s done is °dONLNdÑÈ≠ı⁄)ï7to send the PostScriptBegin PicComment. This comment is°dONLNdºı(64recognized only by PostScript printer drivers. When °dONLNdı⁄)˙*the driver receives this comment, it saves°dONLNd
  5818. v()6the current state of °dONLNd0v
  5819. ⁄)^Hthe PostScript device (by executing the PostScript gsave operator), then°dONLNdy
  5820. ã(56disables all QuickDraw °dONLNdê
  5821. ã⁄)sAdrawing operations. This way, the QuickDraw representation of the°dONLNd“%π(A6Igraphic will be ignored by PostScript devices. In the above example, the °dONLNdπ%⁄(A◊second°dONLNd"%1t(M6EMoveTo/LineTo combination is executed only on non-PostScript devices.°dONLNdh=I*5The next PicComment is PostScriptHandle, which tells °dONLNdù=I⁄(e='the driver that the data in thePSHandle°dONLNd≈IUø(q6[is to be sent to the device as PostScript code. The driver then passes this code unchanged °dONLNd IøU⁄(q›to the°dONLNd'Uav(}6APostScript device for execution. The PostScriptHandle comment is °dONLNdhUva⁄(}îrecognized only by°dONLNd{amì(â6PostScript printer drivers.°dONLNdóyÖD*@The last PicComment, PostScriptEnd, tells the driver to restore °dONLNd◊yDÖ⁄(°b the previous state of the device°dONLNd¯ÖëÜ(≠6M(via a PostScript grestore call), and to enable QuickDraw drawing operations.°dONLNdFù©å*>Since most PicComments are ignored by QuickDraw devices, only °dONLNdÑùå©⁄(≈™
  5822. the QuickDraw°dONLNdí©µs(—6Jrepresentation is printed. Since PostScriptBegin tells PostScript drivers °dONLNd‹©sµ⁄(—ëto ignore QuickDraw°dONLNdµ¡h(›6operations, only °dONLNd    µh¡⁄)POthe PostScript representation is printed on PostScript devices. This is a truly°dONLNd    Q¡Õ≠(È6device-independent method for °dONLNd    o¡≠Õ⁄)ï<providing both PostScript and QuickDraw representations of a°dONLNd    ¨ÕŸJ(ı6    document.
  5823. °dONLNd    ∂Ò-*''Macintosh PICT-to-PostScript conversion
  5824. °dONLNd    fi >* Written:°dONLNd    Ád Ç)L8/3/90°dONLNd    Ó ](46Last reviewed:°dONLNd    ˝ dà)L10/8/91°dONLNd
  5825. $0e(L6EHow do I convert PICT format data to PostScript in my printer driver?°dONLNd
  5826. K0<** ___°dONLNd
  5827. OHTv*FConverting PICT files to PostScript involves a detailed understanding °dONLNd
  5828. ïHvT⁄(pîof both bitmaps (or°dONLNd
  5829. ©T`ª(|6#pixmaps) and the graphics state in °dONLNd
  5830. ÃTª`⁄)£=PostScript, which is a data structure defining the context in°dONLNd
  5831. `l5(à68which other graphic operators in PostScript execute. If °dONLNd B`5l⁄(àSyou don’t know PostScript, the°dONLNd alx¶(î6following manuals are a must:°dONLNd Ñê*•°dONLNd ÅÑ!êé)    PostScript Language °dONLNd ïÑéê⁄)m<Tutorial and Cookbook (Addison-Wesley) is an introduction to°dONLNd “ê!úx(∏?DPostScript. • PostScript Language Reference Manual (Addison-Wesley). ◊4◊˘
  5832. (Ï62) of 22(ÏñBasic QuickDraw Q&Asˇ
  5833. ◊#ˇ ˇˇˇˇ#◊ 
  5834. IR,Times
  5835. .+Z-Developer Support Center(-Ê October 1992 /X/
  5836. °dONLNd<)@(EZ•°dONLNdE)ü)    <PostScript Language Program Design (Addison-Wesley) details °dONLNd>ü)˛(EΩdesigning efficient°dONLNdR)E5ı(Qc%PostScript programs. It has a lot of °dONLNdw)ı5˛)∞5useful sample programs on topics like writing a print°dONLNd≠5EAl(]cspooler.°dONLNd∂M<Y:(uZ1You need to convert all the QuickDraw operations °dONLNdÁM:Y˛)˛%in a PICT to corresponding PostScript°dONLNd
  5837. Y<eu(ÅZ operations. °dONLNdYue˛)9MTo get a feel for this conversion, you can analyze the PostScript dump from a°dONLNdge<q¬(çZKLaserWriter to see how it converts a PICT to PostScript. Under System 6.x, °dONLNd≤e¬q˛(ç‡ a PostScript°dONLNdøq<}(ôZUdump can be obtained by pressing Command-K while printing. Under System 7.0, you can °dONLNdq}˛(ôget°dONLNd}<âp(•ZCa dump by selecting the PostScript File option in the Print dialog.°dONLNd\ï<°ı*NSome areas of QuickDraw, such as transfer modes, do not have a correspondence °dONLNd™ïı°˛(Ωin°dONLNd≠°<≠â(…ZGPostScript. The PostScript imaging model is designed so that all areas °dONLNdÙ°â≠˛(…ßof a page affected by an°dONLNd
  5838. ≠<πn(’Z
  5839. image are °dONLNd≠nπ˛)2Lmarked as if with opaque paint. Using image masks can help. See the Graphics°dONLNddπ<≈(·Z+chapter in the PostScript reference manual.°dONLNdê—<›*,PICT-to-PostScript conversion can be a long °dONLNdº—›˛)„-process, especially if one is unfamiliar with°dONLNdÍ›<ȯ(Z&PostScript. Using the above books and °dONLNd›¯È˛)º2the PostScript dump from the LaserWriter (but ONLY°dONLNdCÈ<ı“(Z as a general guide) should help.
  5840. °dONLNdd
  5841. <D*''Calling InitCursor instead of SetCursor
  5842. °dONLNdå<(b* Written:°dONLNdïà(≤)L10/23/90°dONLNdû(<4Å(PZLast reviewed:°dONLNd≠(à4¨)L2/20/91°dONLNdµ@<Lè(hZGIs it legal to call InitCursor instead of SetCursor(arrow) when I want °dONLNd¸@èL˛(h≠to set the cursor to an°dONLNdL<Xå(tZarrow (after my °dONLNd$LåX˛)PInormal one-time program initialization code, in my UpdateCursor routine)?°dONLNdnX<dI(ÄZ6The only reason I'd want to do such a skanky thing is °dONLNd§XId˛(Äg$to save code. Calling a trap with no°dONLNd…d<pí(åZparameters is less °dONLNd‹díp˛)VJcode than one with parameters. What, exactly, if anything, does InitCursor°dONLNd'p<|§(òZOdo besides setting the cursor to an arrow and setting the cursor level to zero?°dONLNdw|<àN* ___°dONLNd{î<†U*8There's no problem at all with this, as long as you are °dONLNd≥îU†˛(ºs aware that the hidden, busy, and°dONLNd‘†<¨Ÿ(»Z!obscured states are cleared when °dONLNdı†Ÿ¨˛)ù<you call InitCursor, so if the cursor was hidden or obscured°dONLNd2¨<∏A(‘Z:for good reason it'll suddenly reappear. It also gets the °dONLNdl¨A∏˛(‘_$arrow from QuickDraw, of course, but°dONLNdë∏<ƒû(‡Zthat's not a problem.
  5843. °dONLNdß‹<Î◊*'PICT fontName opcode
  5844. °dONLNdºÎ<˜b* Written:°dONLNd≈Îà˜≤)L10/31/90°dONLNdŒ˜<Å(ZLast reviewed:°dONLNd›˜à¨)L2/20/91°dONLNdÂ<¡(7ZRIs there an up-to-date canonical source for PICT opcodes? In “Night of the Living °dONLNd7¡˛(7fl
  5845. Disc,” as far°dONLNdE<'I(CZ6as I can see, the only list of PICT opcodes is in the °dONLNd{I'˛(Cg Macintosh Tech Note “QuickDraw’s°dONLNdú'<3√(OZPInternal Picture Definition” which does not mention opcode $2C. It appears that °dONLNdÏ'√3˛(O·
  5846. opcode $2C°dONLNd˜3<?Ù([ZRconcerns font names. I recall seeing a patch for PictDetective named "fontnameop" °dONLNd    I3Ù?˛([or°dONLNd    L?<K≠(gZMsomething like that. However I can't be sure that $2C is the only new opcode.°dONLNd    öK<WN* ___°dONLNd    ûc<oÜ*@The fontName opcode is documented in the Technical Note “32-Bit °dONLNd    ficÜo˛(ã§QuickDraw: Version 1.2°dONLNd    ıo<{fi(óZXFeatures.” Note also that since the introduction of 32-Bit QuickDraw there are two more °dONLNd
  5847. Mofi{˛(ó¸bitmap°dONLNd
  5848. T{<áÏ(£ZQopcodes for direct RGB PixMaps $009A (DirectBitsRect) and $009B (DirectBitsRgn). °dONLNd
  5849. •{Ïá˛(£
  5850. The°dONLNd
  5851. ©á<ìv(ØZ
  5852. QuickDraw °dONLNd
  5853. ≥ávì˛):Nsection of Inside Macintosh Volume VI has all these opcodes listed in a single°dONLNd ì<ü√(ªZRplace, making it easier to get the necessary info. Here is the info on font names °dONLNd Tì√ü˛(ª· and pictures°dONLNd aü<´ («Z)from the "32-Bit QuickDraw..." Tech Note: ◊X◊
  5854. *%Basic QuickDraw Q&As(Ïˇ3) of 22ˇ◊#ˇ ˇˇˇˇ#◊ 
  5855. IR,Times
  5856. .+6-Macintosh Technical Notes /4/˘
  5857. °dONLNd)5“*$#PICTs Contain Font Name Information°dONLNd$AM~*JEvery time you draw text inside of an _OpenPicture and _ClosePicture pair,°dONLNdoMYÉ* KQuickDraw stores the name of the current font and uses it when playing back°dONLNdªYeÉ* Nthe picture. The opcode used to save this information is $002C and its data is°dONLNd
  5858. eqL* as follows:,
  5859. Courier
  5860.     °dONLNd}àê*   PictFontInfo = Record°dONLNd/áív*
  5861. F                    length   : Integer;    { length of data in bytes }°dONLNdvëúv*
  5862. F                    fontID   : Integer;    { ID in the source system }°dONLNdΩõ¶÷*
  5863. &                    fontName : Str255;°dONLNd‰•∞Ü*
  5864.                   END;
  5865. °dONLNd˚ª«á*EQuickDraw saves this information only one time for each font used in °dONLNd@ªá«⁄(„•a picture. When°dONLNdP«”X(Ô6BQuickDraw plays back a picture, it uses the fontID as a reference °dONLNdí«X”⁄(Ôvinto the list of font names°dONLNdÆ”fl*(˚6<which are used to set the correct font on the target system.°dONLNdÎΘµ* For example, the following code:
  5866.     °dONLNd q*E   GetFNum('Venice', theFontID);    { Set a font before opening PICT}°dONLNdR
  5867. ã*
  5868.    TextFont(theFontID);°dONLNdj!,Ã*$   pHand2 := OpenPicture (pictRect);°dONLNdè+6Å*
  5869.        MoveTo(20,20);°dONLNd•5@€*
  5870. '       DrawString(' Better be Venice');°dONLNdÕITÃ*$       GetFNum('Geneva', theFontID);°dONLNdÚS^ü*
  5871.        TextFont(theFontID);°dONLNd]hÅ*
  5872.        MoveTo(20,40);°dONLNd$gr§*
  5873.        DrawString('Geneva');°dONLNdA{Ü÷*&       GetFNum('New York', theFontID);°dONLNdhÖêü*
  5874.        TextFont(theFontID);°dONLNdÑèöÅ*
  5875.        MoveTo(20,60);°dONLNdöô§Æ*
  5876.        DrawString('New York');°dONLNdπ≠∏Ã*$       GetFNum('Geneva', theFontID);°dONLNdfi∑¬ü*
  5877.        TextFont(theFontID);°dONLNd˙¡ÃÅ*
  5878.        MoveTo(20,80);°dONLNdÀ÷§*
  5879.        DrawString('Geneva');°dONLNd-’‡h*
  5880.    ClosePicture;
  5881. °dONLNd>Θ*:generates a picture containing font information like this:
  5882.     °dONLNdy|*   OpCode 0x002C {9,°dONLNdé
  5883. q*
  5884. E       "0005 0656 656E 6963 65"}          /* save current font     */°dONLNd‘"r*
  5885.    TxFont 'venice'°dONLNdÁ!,Â*
  5886. )   DHDVText {20, 20, " Better be Venice"}°dONLNd+6q*
  5887. E   OpCode 0x002C {9,                      /* save next font name   */°dONLNdW5@∏*
  5888.         "0003 0647 656E 6576 61"}°dONLNdx?Jr*
  5889.    TxFont 'geneva'°dONLNdãITê*
  5890.    DVText {20, "Geneva"}°dONLNd§S^v*
  5891. F   OpCode 0x002C {11,                     /* ditto                  */°dONLNdÎ]h—*
  5892. %       "0002 084E 6577 2059 6F72 6B"}°dONLNdgrw*
  5893.    TxFont 'newYork'°dONLNd%q|ö*
  5894.    DVText {20, "New York"}°dONLNd@{Üg*
  5895. C   TxFont 'geneva'                        /* second Geneva does not°dONLNdÑÖêg*
  5896. C                                          need another $002C guy */°dONLNd»èöê*
  5897.    DVText {20, "Geneva"} ◊4◊˘
  5898. *64) of 22(ÏñBasic QuickDraw Q&Asˇ◊#ˇ ˇˇˇˇ#◊ 
  5899. IR,Times
  5900. .+Z-Developer Support Center(-Ê October 1992 /X/
  5901. °dONLNd<)…(EZVThis feature works regardless of the type of picture being saved, including old style °dONLNdV…)˛(EÁ
  5902. PICTs in a°dONLNda)<5S(QZ5black-and-white port. Using _OpenCPicture instead of °dONLNdñ)S5˛(Qq!_OpenPicture to start a recording°dONLNd∏5<A˚(]Z*session results in the same functionality.°dONLNd„M<Yb*X-Refs:°dONLNdÎY<eƒ* Inside Macintosh Volume VI°dONLNde<qÄ* BMacintosh Technical Note “QuickDraw's Internal Picture Definition”°dONLNdIq<}Ñ* AMacintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  5903. °dONLNdãï<§*' Using PicComments to rotate text
  5904. °dONLNd¨§<∞b* Written:°dONLNdµ§à∞≤)L11/28/90°dONLNdæ∞<ºÅ(ÿZLast reviewed:°dONLNdÕ∞àº≤)L12/19/90°dONLNd÷»<‘(Z\I have a PostScript routine (using TextBegin/TextEnd) to generate bitmapped rotated text on °dONLNd2»‘˛(the°dONLNd6‘<‡Å(¸Zscreen (which °dONLNdD‘Ҳ)EOcan be later printed on QuickDraw printers). Why do I get duplicate text? I get°dONLNdî‡<Ï*(Z3both bitmapped rotated text and PostScript rotated °dONLNd«‡*Ï˛)Ó,text when I print on the LaserWriter II, and°dONLNdÙÏ<¯Ö(ZDboth bitmapped rotated text and horizontal text on the ImageWriter. °dONLNd8ÏÖ¯˛(£When I make a machine°dONLNdN¯<o( Z
  5905. dependent °dONLNdX¯o˛)3Tcheck (check type of printer) and call the proper printing procedure, it works fine.°dONLNd≠<5(,Z/Because of the speed and memory considerations °dONLNd‹5˛)˘(of generating the rotated bitmapped text°dONLNd<—(8Z[(especially at 300 dpi), is there a way to ensure that the printer will use the PostScript °dONLNd`—˛(8ÔBEFORE°dONLNdg<(¶(DZgenerating the bitmap?°dONLNd~(<4N* ___°dONLNdÇ@<Lz* We will use °dONLNdé@zL˛)>Ithe following Macintosh PicComments to hide your QuickDraw calls from the°dONLNdÿL<X(tZ/LaserWriter, but the ImageWriter will use them:,
  5906. Courier
  5907.     °dONLNdd<oá*PostScriptBegin°dONLNdn<yw*
  5908. ? >> Put your CopyBits and QuickDraw calls to image your rotated°dONLNdXx<É√*
  5909.  >> bitmapped text here....°dONLNdtÇ<ç}*
  5910.  
  5911. PostScriptEnd
  5912. °dONLNdÇò<§®*By wrapping your °dONLNdìò®§˛)l;QuickDraw code within the PostScriptBegin and PostScriptEnd°dONLNdœ§<∞€(ÃZSPicComments, the code will be ignored by the LaserWriter, but the ImageWriter will °dONLNd"§€∞˛(Ã˘use the°dONLNd*∞<º(ÿZSQuickDraw calls. Basically, the PostScriptBegin and PostScriptEnd PicComments tell °dONLNd}∞º˛(ÿthe°dONLNdź<»Ô(‰ZZLaserWriter driver to turn “off” QuickDraw. In the ImageWriter case, the ImageWriter does °dONLNd€ºÔ»˛(‰
  5913. not°dONLNdfl»<‘¨(ZJunderstand the PicComments. Therefore, it will use the QuickDraw calls to °dONLNd)»¨‘˛( create and image°dONLNd:‘<‡û(¸Zyour bitmapped text.°dONLNdPÏ<¯!*-Now, we need to use the rotation PicComments °dONLNd}Ï!¯˛)Â/to rotate the text on the LaserWriter, but have°dONLNd≠¯<÷( Z the ImageWriter ignore the code:
  5914.     °dONLNdŒ<á*Rect  zeroRect;°dONLNdfi$</‹* SetRect (&zeroRect, 0, 0, 0, 0);°dONLNdˇ8<Ci*    TextBegin°dONLNd    B<Mn*
  5915.  
  5916. TextCenter°dONLNdL<W√*
  5917.       ClipRect (&zeroRect);°dONLNd0`<kh*<      >> Draw your text to be rotated on the LaserWriter....°dONLNdmt<»*      ClipRect (&rPageRect);°dONLNdä~<â_*
  5918. TextEnd
  5919. °dONLNdíî<†‘*XWrapping your text drawing call(s) between the ClipRect calls will ensure that the text °dONLNdÍ˛(ºÚis drawn°dONLNdÛ†<¨Û(»ZVonly on the LaserWriter. Setting the ClipRect to zero tells the ImageWriter to ignore °dONLNd    I†Û¨˛(»all ◊X◊
  5920. (ÏZBasic QuickDraw Q&As(Ïˇ5) of 22ˇö◊#ˇ ˇˇˇˇ#◊ 
  5921. IR,Times
  5922. .+6-Macintosh Technical Notes /4/˘
  5923. °dONLNd)ö*QuickDraw calls until the °dONLNdö)⁄)Ç@ClipRect is reset to something “real” (actually, a zero ClipRect°dONLNd[)5ô(Q6prevents QuickDraw from °dONLNds)ô5⁄)Å>drawing anything). After we have completed drawing the rotated°dONLNd≤5A£(]6text, we reset the ClipRect to °dONLNd—5£A⁄)ãAthe dimensions of rPage (that is, rPage is the image-able area of°dONLNdAMJ(i6@the currently selected printer—see Inside Macintosh, Volume II, °dONLNdSAJM⁄(ihpage 150). This will allow all°dONLNdrMYb(u6of your normal °dONLNdÅMbY⁄)JLdrawing to continue on the ImageWriter and LaserWriter. If you did not reset°dONLNdŒYeÿ(Å6%the ClipRect after the TextEnd call, °dONLNdÛYÿe⁄)¿,nothing would be drawn on the ImageWriter or°dONLNd eqT(ç6 LaserWriter.
  5924. °dONLNd-âòO*'*Using dithered drawing mode with QuickDraw
  5925. °dONLNdXò§>* Written:°dONLNdaòd§é)L11/28/90°dONLNdj§∞](Ã6Last reviewed:°dONLNdy§d∞é)L12/19/90°dONLNdǺ»Æ(‰6NWhen I draw a 32-bit Macintosh PICT image from a file to an 8-bit port via an °dONLNd–ºÆ»⁄(‰à   offscreen°dONLNd⁄»‘ (67GWorld, I use dither mode in the CopyBits call and the °dONLNd» ‘⁄(>)results are quite impressive. If there is°dONLNd;‘‡o(¸6Dnot enough memory to allocate the GWorld, I draw the image directly °dONLNd‘o‡⁄(¸çto the port. But since°dONLNdñ‡Ï⁄(6*there does not seem to be any way to tell °dONLNd¿‡⁄Ï⁄)¬1QuickDraw to use dithered drawing mode, the image°dONLNdÚϯ^(6looks horrible.°dONLNd(*9Do you have any suggestions? I have installed bottleneck °dONLNd;(⁄(,F%procs to allow DrawPicture to get its°dONLNda€(86,data from the file instead of the handle in °dONLNdç€⁄)√4memory. Is there a way, while in the bottlenecks, to°dONLNd¬(—(D6'find the CopyBits call that comes from °dONLNdÈ—(⁄)π8the picture and force it to use dithered mode instead of°dONLNd"(4o(P6Bsource mode? I don’t want to try and parse the PICT myself, but I °dONLNdd(o4⁄(Pçthought that maybe a°dONLNdy4@ë(\6QuickDraw global could °dONLNdê4ë@⁄)yAbe modified in my StdBits proc to force dithered drawing for that°dONLNd“@La(h6operation only?°dONLNd‚LX** ___°dONLNdÊdpÃ*^You can install a StdBits or bitsProc bottleneck procedure to get all the CopyBits calls when °dONLNdDdÃp⁄(åÍthe°dONLNdHp|{(ò6Kpicture is being played back. One of the parameters to the StdBits call is °dONLNdìp{|⁄(òôthe mode. You can°dONLNd•|à8(§6install °dONLNd≠|8à⁄) Sa procedure that saves the current mode, and then passes ditherMode to the original°dONLNdàîï(∞6PStdBits proc. This is all you should need to do. It’s been done here so we know °dONLNdQàïî⁄(∞≥it works, only°dONLNd`î†Q(º6Dnot in any form that can be sent to you as sample code at this time.
  5926. °dONLNd•∏«9*'(Code for reversing Macintosh PICT images
  5927. °dONLNdŒ«”>* Written:°dONLNd◊«d”Ç)L3/4/91°dONLNdfi”fl](˚6Last reviewed:°dONLNdÌ”dflà)L8/30/91°dONLNdıΘF(6 Is there a °dONLNdÎF˜⁄).Psimple way to put PICT images up in mirror image format, or is there sample code°dONLNdQ˜›(6(showing how to flip an offscreen bitmap?°dONLNdz** ___°dONLNd~'ã*KThere is no easy way to do this, nor do we have sample code showing how to °dONLNd…ã'⁄(C©flip an offscreen°dONLNd€'3ø(O6#bitmap. Indeed, the best way to do °dONLNd˛'ø3⁄)ß9what you want is to draw it to an offscreen pixel map and°dONLNd    83?G([6 reverse it.°dONLNd    DKWÑ*If you are using Color °dONLNd    [KÑW⁄)lEQuickDraw, always draw it to an 8-bit-per-pixel offscreen bitmap, and°dONLNd    °WcÃ(6(then the reverse is a very simple task. °dONLNd    …WÃc⁄)¥5Here is some sample Pascal code that might roughly do°dONLNd    ˇco˝(ã6.what you want, with the following assumptions:°dONLNd
  5928. .{á7*=    1. You are going to add error checking where appropriate.°dONLNd
  5929. láì9* >    2. Rowbytes correspond exactly to pixel width of the port.°dONLNd
  5930. ´ìüû*     3. The port is 8 bits deep.°dONLNd
  5931. Àü´* 1    4. You add the code to make this sketch work. ◊4◊˘
  5932. *%6) of 22(ÏñBasic QuickDraw Q&Asˇ◊#ˇ ˇˇˇˇ#◊ 
  5933. IR,Times
  5934. .+Z-Developer Support Center(-Ê October 1992 /X/
  5935. °dONLNd<)(EZ2    5. The origin of your offscreen port is (0,0).,
  5936. Courier
  5937.     °dONLNd35<@O*7Procedure FlipScanLine(theV:Integer; thePort:cGrafPtr);°dONLNdk?<J∏*
  5938. L{ Given any scan line number in the indicated port, this routine will flip }°dONLNd∏I<T∏*
  5939. L{ that scan line horizontally. This routine assumes that you have made     }°dONLNdS<^*
  5940. ${ sure that scan line theV exists. }°dONLNd*g<r*(type ScanLn=Packed Array [0..0] of Byte;°dONLNdSq<|•*
  5941.    ScanPtr=^ScanLine;°dONLNdi{<Ü¥*
  5942. var thePixMap:PixMapPtr;°dONLNdÇÖ<ê™*
  5943.    Index,Size:Integer;°dONLNdôè<ö¥*
  5944.    ThisScanLine:ScanPtr;°dONLNd≤ô<§ñ*
  5945.    TempPixel:Byte;°dONLNd≈≠<∏U*Begin°dONLNdÀ∑<¬·*
  5946. ! thePixMap:=thePort^.PortPixMap^;°dONLNdÌ¡<Ãü*
  5947. G{ First create a pointer to the scan line we are currently reversing. }°dONLNd5À<÷*
  5948. , ThisScanLine:=ScanPtr(thePixMap^.BaseAddr);°dONLNdb’<‡ö*
  5949. F ThisScanLine:=ScanPtr(ord4(ThisScanLine)+(thePixMap^.RowBytes*theV));°dONLNd©È<Ùı*%{ Now simply reverse all the bytes. }°dONLNdœÛ<˛Ω*
  5950. M{ The scan line is simply an array [0..RowBytes] of Byte, and since this is }°dONLNd˝<,*
  5951. 0{ 8 bits per pixel, each one is a single pixel.}°dONLNdN<√*
  5952.  Size:=thePixMap^.RowBytes;°dONLNdj<‹*
  5953.   For Index:=0 to (Size div 2) do°dONLNdã<&_*
  5954.   begin°dONLNdì%<0Î*
  5955. #   tempPixel:=ThisScanLine^[Index];°dONLNd∑/<:@*
  5956. 4   ThisScanLine^[Index]:=ThisScanLine[Size-Index-1];°dONLNdÏ9<DÎ*
  5957. #   ThisScanLine^[Index]:=tempPixel;°dONLNdC<NZ*
  5958.   end;°dONLNdM<XP*
  5959. end;
  5960. °dONLNdc<o¬*This same procedure can be °dONLNd7c¬o˛)ÜAused also to swap a 1-, 2- or 4-bit-per-pixel pixmap if you add a°dONLNdyo<{9(óZ8function that accepts a byte and swaps the pixels in it.
  5961. °dONLNd≤ì<¢ª*'7Use srcOr instead of srcCopy for Macintosh text drawing
  5962. °dONLNdÍ¢<Æb* Written:°dONLNdÛ¢àƶ)L6/4/91°dONLNd˙Æ<∫Å(÷ZLast reviewed:°dONLNd    Æà∫¨)L10/9/91°dONLNdΔ<“=(ÓZ1DrawText with srcCopy takes six times as long as °dONLNdBΔ=“˛(Ó[#with srcOr now that my Macintosh is°dONLNdf“<fiw(˙ZArunning System 7. Why is this so slow? Is this a bug in System 7?°dONLNd®fi<ÍN* ___°dONLNd¨ˆ<Æ*It’s true that srcCopy is °dONLNdΔˆÆ˛)rDslower than srcOr when handling text, especially in color mode. This°dONLNd <(*Z&loss in speed occurs because CopyBits °dONLNd1˛)Δ2is a lot smarter than it used to be. It can handle°dONLNdd<®(6ZLforeground and background colors a lot better, but that improvement came at °dONLNd∞®˛(6Δthe cost of speed.°dONLNd√<&=(BZ4Our recommended method for drawing text is to erase °dONLNd˜=&˛(B[&before drawing, and use srcOr to draw,°dONLNd&<2‘(NZSnot srcCopy. Alternatively, you could draw colorized text in srcOr mode off screen °dONLNdq&‘2˛(NÚand then°dONLNdz2<>¶(ZZKuse CopyBits to draw it on the screen in srcCopy mode without colorization.
  5963. °dONLNdΔV<e>*'%Techniques for graying Macintosh text
  5964. °dONLNdÏe<qb* Written:°dONLNdıeàq¶)L6/3/91°dONLNd¸q<}Å(ôZLast reviewed:°dONLNd qà}¶)L8/1/91°dONLNdâ<ïÅ(±ZBHow do I draw grayed-out text on the Macintosh, like the text for °dONLNdTâÅï˛(±üdisabled buttons or menu°dONLNdmï<°Z(ΩZitems?°dONLNdt°<≠N* ___ ◊X◊
  5965. *#Basic QuickDraw Q&As(Ïˇ7) of 22ˇ&◊#ˇ ˇˇˇˇ#◊ 
  5966. IR,Times
  5967. .+6-Macintosh Technical Notes /4/˘
  5968. °dONLNd)5U*$FThere are currently two different kinds of grayed text: First, there’s°dONLNdH5Aƒ* $“patterned” gray, where every other °dONLNdl5ƒA⁄)¨8dot is missing. This really only looks good with Chicago°dONLNd•AM-(i65or other heavy fonts and was always used for graying °dONLNd⁄A-M⁄(iK out menus and controls in system°dONLNd˚MY(u66software through 6.0.x, and is still used in 7.0 when °dONLNd1MY⁄)˝+the screen is set to less than 4 bits deep.°dONLNd]Ye∞(Å6This is done by first drawing °dONLNd{Y∞e⁄)ò8the text in a normal, srcCopy transfer mode. Then a gray°dONLNd¥eqq(ç6rectangle is drawn °dONLNd«eqq⁄)YMover the text using the patBic mode. This “erases” half the bits in the text,°dONLNdq}(ô6:and is rapid enough that there is very rarely any flicker.°dONLNdPâï(*<The second kind of text is the actually gray text, which is °dONLNdåâ(ï⁄(±F$used in System 7 on screens that are°dONLNd±ï°Ñ(Ω6J4 bits deep or deeper for menus, controls, and other grayed text. To draw °dONLNd˚ïѰ⁄(Ω¢this text, just call°dONLNd°≠Ñ(…6HGetGray (as documented on page 17-27 of Inside Macintosh, Volume VI) to °dONLNdX°Ñ≠⁄(…¢get an appropriate°dONLNdk≠πÀ(’6'gray. Then draw the text in that color.
  5969. °dONLNdì—‡Ñ*'3Updating Macintosh cursor without mouse competition
  5970. °dONLNd«‡Ï>* Written:°dONLNd–‡dÏà)L6/12/91°dONLNdÿϯ](6Last reviewed:°dONLNdÁÏd¯Ç)L8/1/91°dONLNdÓ (,6WHow can I programmatically move the Macintosh mouse without the real mouse interfering?°dONLNdF** ___°dONLNdJ(4q*GThe real answer to your question is twofold: First, you can do exactly °dONLNdë(q4⁄(Pèwhat you want to do°dONLNd•4@d(\6Bwith the sample included below. HOWEVER, this is not a good thing °dONLNdÁ4d@⁄(\Çto do, it would be better°dONLNd@LO(h6 if you took °dONLNd
  5971. @OL⁄)7Othe solution used in Apple’s Guided Tour disks: Always hide the cursor and then°dONLNd]LXÁ(t6*decouple the cursor from the mouse. Then, °dONLNdáLÁX⁄)œ1instead of using the system’s cursor, simply draw°dONLNdπXd(Ä64your own “cursor” using QuickDraw and treat it as a °dONLNdÌXd⁄)˚*little animated bitmap on the screen. This°dONLNddp(å6/avoids all the problems that you have with the °dONLNdGdp⁄)Ì'mouse competing. (Apple does update the°dONLNdop|ã(ò6Omouse globals with the mouse position so that other things function correctly.)°dONLNdøàî≠*PNow, as promised, here is the way to do what you want using the real cursor. As °dONLNdà≠î⁄(∞Àyou have°dONLNdî†(º65discovered, setting the crsrCouple variable to false °dONLNdMî†⁄)ˇ&prohibits the mouse from affecting the°dONLNdt†¨B(»6?cursor; unfortunately, it also prohibits the jcrsrTask routine °dONLNd≥†B¨⁄(»`from drawing the cursor. The°dONLNd–¨∏‰(‘60solution to this is to set crsr couple to true, °dONLNd¨‰∏⁄)Ã3call the cursor drawing routine jCrsrTask yourself,°dONLNd4∏ƒ<(‡6>and then set the crsrCouple variable to false, as shown below:,
  5972. Courier
  5973.     °dONLNds–€w*procedure callcrsr;°dONLNdá⁄ÂÂ*
  5974. )              inline $2078 ,$08EE ,$4E90;°dONLNd±‰Ô«*
  5975. #{            move.L    jcrsrTask,A0°dONLNd’Ó˘*
  5976. 4            jsr    (A0)                            }°dONLNd    
  5977. 
  5978. Å*Procedure FudgeMouse;°dONLNd     !ê*type    PointPtr=^Point;°dONLNd    9*5©*var        RawMouse:PointPtr;°dONLNd    W4?ã*
  5979.         MTemp:PointPtr;°dONLNd    o>IÅ*
  5980.         RandPt:Point;°dONLNd    ÖHS|*
  5981.         CrsrNew:ptr;°dONLNd    öR]ã*
  5982.         CrsrCouple:ptr;°dONLNd    ≤\gÅ*
  5983.         fred:Longint;°dONLNd    –p{1*begin°dONLNd    ÷zÖΩ*
  5984. !        RawMouse:=PointPtr($82C);°dONLNd    ¯ÑèÆ*
  5985.         MTemp:=PointPtr($828);°dONLNd
  5986. éôü*
  5987.         CrsrNew:=ptr($8CE);°dONLNd
  5988. 3ò£Æ*
  5989.         CrsrCouple:=ptr($8CF);°dONLNd
  5990. R¢≠ö*
  5991.         RandPt:=RawMouse^; ◊4◊˘
  5992. *#8) of 22(ÏñBasic QuickDraw Q&Asˇä◊#ˇ ˇˇˇˇ#◊ 
  5993. IR,Times
  5994. .+Z-Developer Support Center(-Ê October 1992 /X/,
  5995. Courier
  5996.     °dONLNd<(Ç(DZ        repeat°dONLNd'<2·*
  5997. !            RandPt.h:=RandPt.h+1;°dONLNd11<<·*
  5998. !            RandPt.V:=RandPt.v+1;°dONLNdS;<F“*
  5999.             RawMouse^:=RandPt;°dONLNdrE<P√*
  6000.             MTemp^:=RandPt;°dONLNdéO<Z¥*
  6001.             CrsrNew^:=1;°dONLNdßY<d√*
  6002.             CrsrCouple^:=1;°dONLNd√c<n•*
  6003.             callCrsr;°dONLNdŸm<x√*
  6004.             crsrCouple^:=0;°dONLNdıw<Ç*
  6005. (            repeat until fred<tickCount;°dONLNdÅ<å“*
  6006.             fred:=tickCount+3;°dONLNd=ã<ñ•*
  6007.         until Button;°dONLNdSï<†Ø*
  6008.         crsrCouple^:=1;°dONLNdkü<™P*
  6009. end;
  6010. °dONLNdp¡<–g*&'System 7 QuickDraw DrawText performance
  6011. °dONLNdò–<‹b* Written:°dONLNd°–à‹¨)L11/4/91°dONLNd©‹<ËÅ(ZLast reviewed:°dONLNd∏‹àË≤)L11/27/91°dONLNd¡Ù<^(ZWe’ve °dONLNd«Ù^˛)"Rnoticed that using DrawText is much slower in System 7, especially when drawing in°dONLNd< ¢((Zcolor (anything other °dONLNd0¢ ˛)fFthan black on white). What can be done to restore the drawing speed to°dONLNdw <ã(4ZSystem 6 levels?°dONLNdà<$N* ___°dONLNdå0<<ê*9A QuickDraw function like DrawString or DrawText will be °dONLNd≈0ê<˛(XÆslower under certain°dONLNd⁄<<H∑(dZMcircumstances in System 7 than System 6. Specifically, if you are drawing in °dONLNd'<∑H˛(d’ srcCopy mode°dONLNd4H<T‚(pZVand you colorize the text—that is, foreground color is not black and background color °dONLNdäH‚T˛(pis not°dONLNdëT<`Å(|Z>white (Inside Macintosh Volume VI, page 17-16)—then QuickDraw °dONLNdœTÅ`˛(|üreally slows down as you°dONLNdË`<l¬(àZMhave noticed. SOMETIMES, the speed of drawing is 6 times as slow as System 6.°dONLNd6x<Ñt*<The cause of this slowness is a known System 7 bug. The bug °dONLNdrxtÑ˛(†íhas concerned the engineers°dONLNdéÑ<êã(¨ZHgreatly and will be responded to in an appropriate manner in the future.°dONLNd◊ú<®Ö*BThere are a few workarounds: One, you can avoid using the srcCopy °dONLNdúÖ®˛(ƒ£mode and use the default°dONLNd2®<¥Í(–Z"srcOr mode instead. However, this °dONLNdT®Í¥˛)Æ6is not a real workaround, since you may have essential°dONLNdã¥<¿q(‹Z reasons to °dONLNdñ¥q¿˛)5Luse srcCopy. The other option is to create an offscreen pixmap or GWorld and°dONLNd„¿<Ã˚(ËZ&perform a DrawText with srcOr to this °dONLNd    ¿˚Ã˛)ø1GWorld with colorization. Then, you can perform a°dONLNd;Ã<ÿé(ÙZ@CopyBits from the offscreen to the screen with srcCopy mode and °dONLNd{Ãéÿ˛(Ù¨no colorization. Using°dONLNdíÿ<‰»(ZSCopyBits will not cost you much time. Again, this is a workaround and is not ideal.°dONLNdÁ<¸Î*[The srcOr is a bit slower than in System 6.0.x, but it does not have a bug; rather it is a °dONLNdBθ˛(    side°dONLNdG¸<_($Z=effect of system enhancements. The slow speed is a trade-off °dONLNdѸ_˛($}"taken to receive the host of other°dONLNdß<e(0Z    benefits.
  6012. °dONLNd±,<;˝*'Macintosh animation samples
  6013. °dONLNdÕ;<Gb* Written:°dONLNd÷;àG¨)L11/6/91°dONLNdfiG<SÅ(oZLast reviewed:°dONLNdÌGàS¨)L11/6/91°dONLNdı_<k~(áZBDo you have an example of flicker-free animation on the Macintosh?°dONLNd8k<wN* ___°dONLNd<É<è*'We have some good stuff that’s written °dONLNdcÉè˛)“(in MPW Pascal. It’s DTS Sample Code #16,°dONLNdåè<õv(∑Z OffSample, °dONLNdóèvõ˛):Land this uses some routines defined in DTS Sample Code #15, OffScreen. Also, ◊X◊
  6014. (ÏZBasic QuickDraw Q&As(Ïˇ9) of 22ˇ*◊#ˇ ˇˇˇˇ#◊ 
  6015. IR,Times
  6016. .+6-Macintosh Technical Notes /4/˘
  6017. °dONLNd)v*Fthe System 7.0 CD sample code folder contains a smaller sample called °dONLNdFv)⁄(Eî“GMonde” that uses°dONLNdY)5H(Q6GWorlds.
  6018. °dONLNdbM\‚*'CopyBits bug and workaround
  6019. °dONLNd~\h>* Written:°dONLNdá\dhà)L6/26/91°dONLNdèht](ê6Last reviewed:°dONLNdûhdtà)L8/13/91°dONLNd¶Äåß(®6UHas anyone run across what I’m told is a bug in CopyBits? It works like this: In the °dONLNd˚Äßå⁄(®≈
  6020. deep, dark°dONLNdåò•(¥6workings of CopyBits, some °dONLNd!å•ò⁄)ç@routine tries to read the two bytes preceding the baseAddress of°dONLNdbò§(¿66the source PixMap. If the baseAddress is at the start °dONLNdòò§⁄)¯)of a card’s NuBus space and there isn’t a°dONLNd¬§∞’(Ã6]card filling the adjacent space, this causes a bus error! Has anyone found a good workaround?°dONLNd ∞º** ___°dONLNd$»‘≥*SThe short answer is: you’re right. QuickDraw inadvertently reads from memory below °dONLNdw»≥‘⁄(—the base°dONLNdÄ‘‡¿(¸6Yaddress of a pixmap. The workaround is to place the video base address 32 bytes into the °dONLNdŸ‘¿‡⁄(¸fiRAM°dONLNd›‡Ï(68on the card; if the card you’re using doesn’t have this °dONLNd‡Ï⁄)˛&workaround, there’s nothing you can do°dONLNd<ϯ1(6=other than making sure there’s a card in the next-lower slot.
  6021. °dONLNdzD*'+Macintosh picture (PICT) 90-degree rotation
  6022. °dONLNd¶+>* Written:°dONLNdØd+à)L7/23/91°dONLNd∑+7](S6Last reviewed:°dONLNdΔ+d7à)L8/30/91°dONLNdŒCO}(k6The trick for rotating °dONLNdÂC}O⁄)eHa Macintosh QuickDraw picture 90 degrees is to intercept all bottlenecks°dONLNd.O[¢(w6Tand exchange the x and y coordinates. Then, call OpenPicture to receive the rotated °dONLNdÇO¢[⁄(w¿
  6023. picture, call°dONLNdê[g,(É6:DrawPicture(unrotatedPicture), and then call ClosePicture °dONLNd [,g⁄(ÉJ$on the rotated picture. You’re done!°dONLNdÔgsm(è6QuickDraw spins °dONLNdˇgms⁄)UJout the DrawPicture call into its component parts, but runs each component°dONLNdJs‡(õ6+through the bottlenecks first, so they get °dONLNdus‡⁄)»1rotated (by YOUR bottleneck intercepts) and stuck°dONLNdßã≈(ß6&into the new picture, already rotated.°dONLNdŒó£S*>Here‘s a bottleneck intercept for StdLine that rotates a PICT °dONLNd óS£⁄(øqcomposed entirely of Line°dONLNd&£Ø(À64commands (which depend on the current pen position):,
  6024. Courier
  6025.     °dONLNd[ªΔ«*#procedure MyLineProc(newPt: point);°dONLNd≈–'*
  6026. var°dONLNdÉœ⁄r*
  6027.   tempV : integer;°dONLNdñŸ‰1*
  6028. begin°dONLNdú„Óä*
  6029. J  tempV := thePort^.pnLoc.v;     { Swap current pen location coordinates }°dONLNdÁ̯€*
  6030. '  thePort^.pnLoc.v := thePort^.pnLoc.h;°dONLNd˜§*
  6031.   thePort^.pnLoc.h := tempV;°dONLNd/ ä*J  tempV := newPt.v;          { Swap destination pen location coordinates }°dONLNdz Å*
  6032.   newPt.v := newPt.h;°dONLNdê*w*
  6033.   newPt.h := tempV;°dONLNdß3>m*  StdLine(newPt);°dONLNdºGRä*J  tempV := thePort^.pnLoc.v;  { Restore current pen location coordinates }°dONLNdQ\€*
  6034. '  thePort^.pnLoc.v := thePort^.pnLoc.h;°dONLNd/[f§*
  6035.   thePort^.pnLoc.h := tempV;°dONLNdLep,*
  6036. end;
  6037. °dONLNdQ{á”**Notice that the start coordinates as well °dONLNd{{”á⁄)ª5as the destination coordinates must be swapped before°dONLNd±áìZ(Ø6Bcalling StdLine. The resulting pen location is swapped back again °dONLNdÛáZì⁄(Øxafter the operation, so the°dONLNd    ìü@(ª6?port looks like it should if unrotated drawing were performed. °dONLNd    Nì@ü⁄(ª^For things that don’t depend on°dONLNd    nü´(«6=the current pen location, things are simplified a little bit. ◊4◊˘
  6038. *%10)
  6039.  of 22(ÏñBasic QuickDraw Q&Asˇ
  6040. Ä◊#ˇ ˇˇˇˇ#◊ 
  6041. IR,Times
  6042. .+Z-Developer Support Center(-Ê October 1992 /X/
  6043. °dONLNd)<5—(QZRYou’ll still need bitmap rotation code for the StdBits and StdText intercepts.You °dONLNdR)—5˛(QÔmight do°dONLNd[5<Aí(]ZLStdText by setting the port to an offscreen one you create earlier, calling °dONLNdß5íA˛(]∞QuickDraw’s StdText,°dONLNdºA<Më(iZKand then calling your bitmap rotation code to copy it into the destination.
  6044. °dONLNde<t°*'3Macintosh QuickDraw and pen characteristic routines
  6045. °dONLNd<t<Äb* Written:°dONLNdEtàĨ)L8/12/91°dONLNdMÄ<åÅ(®ZLast reviewed:°dONLNd\Äàå¨)L11/6/91°dONLNddò<§"(¿Z-When generating pictures and then looking at °dONLNdëò"§˛)Ê)the corresponding Macintosh PICT file, we°dONLNdª§<∞v(ÃZ?notice that QuickDraw is optimizing PnMode, PnPat, and PnSize. °dONLNd˙§v∞˛(ÃîCan you tell us how to stop°dONLNd∞<º∂(ÿZHQuickDraw from optimizing, and how to know when QuickDraw will optimize?°dONLNd_º<»N* ___°dONLNdc‘<‡≥*NQuickDraw does not optimize away new pen characteristic routines, but it does °dONLNd±‘≥‡˛(¸—insert them into°dONLNd¬‡<Ïd(Z    pictures °dONLNdÀ‡dÏ˛)(Ujust before a drawing routine that uses the pen rather than place them where they are°dONLNd!Ï<¯‘(ZVcalled. Therefore, you may not see your new pen characteristic routine until later in °dONLNdwÏ‘¯˛(Ú    a picture°dONLNdů<ñ( Zwhen it is about to °dONLNdï¯ñ˛)ZKbe used. Opcodes for pen characteristics are inserted into the picture when°dONLNd·<:(,Z5they are changed from the previous time they’re used.
  6046. °dONLNd(<7∫*'8Detecting whether application window is partially hidden
  6047. °dONLNdP7<Cb* Written:°dONLNdY7àC¨)L9/26/92°dONLNdaC<OÅ(kZLast reviewed:°dONLNdpCàO¨)L1/27/92°dONLNdx[<g#(ÉZ3We draw directly to the screen to gain the fastest °dONLNd´[#g˛)Á*possible animation speed, and when we need°dONLNd÷g<s˜(èZ#compatibility—such as when windows °dONLNd˘g˜s˛)ª3overlap or for multiple screens—we do use CopyBits.°dONLNd-s<Ÿ(õZXHow do we tell whether the window is hidden or that the visible part is not rectangular?°dONLNdÜ<ãN* ___°dONLNdäó<£ï*If your window is °dONLNdúóï£˛)YJcovered partially by another applications window or if your layer has been°dONLNdÁ£<Ø≥(ÀZJhidden by the process menu, the visRgn of your window’s grafport will not °dONLNd1£≥Ø˛(À—be the portRect°dONLNdAØ<ªm(◊Z    anymore. °dONLNdJØmª˛)1P(Keep in mind that if you scroll by modifying the portRect of the grafport, then°dONLNdõª<«O(„Z;you’ll have to do a more complex calculation...) Here is a °dONLNd÷ªO«˛(„m&small Pascal routine that returns this°dONLNd˝«<”v(ÔZ information: ◊X◊
  6048. *˝Basic QuickDraw Q&As(Ï˙11)
  6049.  of 22ˇ
  6050. fi◊#ˇ ˇˇˇˇ#◊ 
  6051. IR,Times
  6052. .+6-Macintosh Technical Notes /4/˘,
  6053. Courier
  6054.     °dONLNd)4˛*#.Function UseCopyBits(thePort:grafptr):Boolean;°dONLNd/=H1*begin°dONLNd9Q\:*:     UseCopyBits:= NOT( (thePort^.VisRgn^^.rgnSize=10) and°dONLNdt[f0*
  6055. 8        (thePort^.visRgn^^.RgnBBox=thePort^.PortRect) );°dONLNd≠ep,*
  6056. end;°dONLNd≤yÑè*KThe rect strucRgn^^.rgnBBox will be zero for a visible window if the system°dONLNdˇÉéü*
  6057. has hidden the application.
  6058. °dONLNd•¥>*&,How to tell whether GetPictInfo is available
  6059. °dONLNdH¥¿>* Written:°dONLNdQ¥d¿é)L12/16/91°dONLNdZ¿Ã](Ë6Last reviewed:°dONLNdi¿dÃà)L2/24/92°dONLNdqÿ‰W(6 How do you °dONLNd|ÿW‰⁄)?Pdetermine whether the function GetPictInfo is available? Gestalt doesn’t seem to°dONLNdÕ‰z( 6have the right stuff?!°dONLNd‰¸** ___°dONLNdË*0To determine whether the GetPictInfo routine is °dONLNd⁄)Î*available, check the system version number°dONLNdC ∑(<6Vwith the Gestalt function. The GetPictInfo routine is available under system software °dONLNdô∑ ⁄(<’version°dONLNd° ,t(H67.0 and later. Use °dONLNd¥ t,⁄)\Ithe Gestalt selector gestaltSystemVersion to determine the version of the°dONLNd˛,8A(T6>system currently running. In most cases you shouldn’t rely on °dONLNd<,A8⁄(T_the system version to determine°dONLNd\8D˘(`62if features are available. However, in this case, °dONLNdé8˘D⁄)·0this is the only way to determine if the Picture°dONLNdøDP¢(l6Utilities Package is available.°dONLNdfl\hú*JSee Inside Macintosh Volume VI page 3-42 for information on using Gestalt °dONLNd)\úh⁄(Ñ∫ to check the°dONLNd6ht6(ê66System version number. See Inside Macintosh Volume VI °dONLNdlh6t⁄(êT page 18-3 for information on the°dONLNdçtÄè(ú6Picture Utilities Package.°dONLNd®åò∂*ZFor example, the following C function will determine if the GetPictInfo call is available:
  6060.     °dONLNd§Øü*    #include <GestaltEQU.h>°dONLNd∏√∏*     Boolean IsGetPictInfoAvail()°dONLNd@¬Õ1*
  6061.     {°dONLNdFÃ◊h*
  6062.       OSErr err;°dONLNdW÷·w*
  6063.       long feature;°dONLNdkÍı&*6         err = Gestalt(gestaltSystemVersion,&feature);°dONLNd¢˛    Ù*,      /*-- check for system 7 and above --*/°dONLNdœ—*
  6064. %      return (feature >= 0x00000700);°dONLNdı1*
  6065.     }°dONLNd˚&1ï*or, if you prefer Pascal:°dONLNd:EÂ*)    function IsGetPictInfoAvail: Boolean;°dONLNd?DO;*
  6066.     var°dONLNdGNYw*
  6067.         err: OSErr;°dONLNd[Xcï*
  6068.         feature: longint;°dONLNdubmE*
  6069.         begin°dONLNdlw&*
  6070. 6        err := Gestalt(gestaltSystemVersion, feature);°dONLNd∂vŞ*
  6071. .        (*-- check for system 7 and above --*)°dONLNdÂÄã!*
  6072. 5        IsGetPictInfoAvail := (feature >= $00000700);°dONLNdäï@*
  6073.     end; ◊4◊˘
  6074. *;12)
  6075.  of 22(ÏñBasic QuickDraw Q&Asˇ¥◊#ˇ ˇˇˇˇ#◊ 
  6076. IR,Times
  6077. .+Z-Developer Support Center(-Ê October 1992 /X/
  6078. °dONLNd<,(HZ!GrafPort patStretch: valid values
  6079. °dONLNd",<8b* Written:°dONLNd+,à8≤)L12/19/91°dONLNd48<DÅ(`ZLast reviewed:°dONLNdC8àD¶)L2/6/92°dONLNdJP<\fi(xZWI’d like to know more about that PatStretch field inside a GrafPort or CGrafPort. If I °dONLNd°Pfi\˛(x¸stuff a°dONLNd©\<hè(ÑZDvalues in PatStretch(4) then nothing happens; prints look the same, °dONLNdÌ\èh˛(Ñ≠even using a standard°dONLNdh<t6(êZ6bottleneck. Please tell me how I can get this to work.°dONLNd:t<ÄN* ___°dONLNd>å<ò?*6PatStretch only works with values of 2 or 3. With any °dONLNdtå?ò˛(¥]*other value, it defaults to no stretching.°dONLNdüò<§(¿Z(The “2” case was created because of the °dONLNd«ò§˛)«1ImageWriter (72->144 dpi) situation. The “3” case°dONLNd˘§<∞Ç(ÃZ?was added to support the ImageWriter LQ and the AppleFax modem.°dONLNd9º<»**So why wasn’t a “4” (72->300 dpi) handler °dONLNdcº»˛)“0added for the LaserWriter driver? Good question.°dONLNdî»<‘r(Z@Somehow or other it was decided that pattern stretching for the °dONLNd‘»r‘˛(êLaserWriter driver would be°dONLNd‘<‡˛(¸Z*done completely by the driver itself. The °dONLNd‘˛‡˛)¬6LaserWriter driver actually does pattern stretching by°dONLNdQ‡<ÏÄ(ZDusing a pattern 4 times as large, rather than 4.17. In other words, °dONLNdï‡ÄÏ˛(ûit really scales the 72 dpi°dONLNd±Ï<¯Ä(Zpattern to 288 °dONLNd¿Ïį˛)DMdpi rather than 300 dpi. You may want to take a similar approach, since you’d°dONLNd¯<%( Z.only have to work with whole numbers this way.°dONLNd=<w*ASo, if you want to do 4-times pattern stretching, you must scale °dONLNd~w˛(8ïthe pattern yourself. If you°dONLNdõ<(ß(DZNcopy the original pattern into an area that’s twice as wide and twice as tall °dONLNdÈß(˛(D≈and use that, you°dONLNd˚(<4œ(PZVshould be all set. You’ll need to use PrGeneral to set the printer to the appropriate °dONLNdQ(œ4˛(PÌ
  6080. resolution°dONLNd\4<@•(\ZPand Copybits to copy the pattern into the object that needs to be filled, using °dONLNd¨4•@˛(\√the “cookie cutter”°dONLNd¿@<L∑(hZapproach to fill the object.°dONLNd›X<d]*X-Ref:°dONLNd‰d<pˆ* %Inside Macintosh Volume I, page I-150
  6081. °dONLNd
  6082. à<óQ*'&Where CopyBits looks for memory to use
  6083. °dONLNd1ó<£b* Written:°dONLNd:óࣶ)L1/3/92°dONLNdA£<ØÅ(ÀZLast reviewed:°dONLNdP£àب)L1/27/92°dONLNdXª<«4(„Z1Where does CopyBits look for the memory it needs?°dONLNdä«<”N* ___°dONLNdéfl<ί*'CopyBits checks the stack to determine °dONLNdµfl¯Î˛)º7if there is enough stack space for it to copy the whole°dONLNdÌÎ<˜4(Z2image, which in some cases may be roughly up to 5 °dONLNdÎ4˜˛)¯*extra rowbytes of special effects per row,°dONLNdJ˜<Δ(ZRdepending on what special effects such as dithering or scaling are being used. If °dONLNdú˜Δ˛(‰ there is not°dONLNd©<‚(+Z!enough stack space for the whole °dONLNd ‚˛)¶8image, CopyBits then tries for half the image, and keeps°dONLNd<V(7Z=halving until it gets down to one row of the image (plus the °dONLNd@V˛(7t#room for the special effects rows).°dONLNdd<'
  6084. (CZ+If there is not enough stack space for one °dONLNdè
  6085. '˛)Œ1row of the image, then CopyBits tries to allocate°dONLNd¡'<3ö(OZtemporary memory.°dONLNd”?<KO*4Before allocating temporary memory, CopyBits checks °dONLNd    ?OK˛(gm!if the temporary memory traps are°dONLNd    )K<W-(sZ3available. (They are available under both System 6 °dONLNd    \K-W˛)Ò+MultiFinder and System 7.) If the traps are°dONLNd    àW<c(ZDavailable, CopyBits tries to allocate a 256K byte buffer for use as °dONLNd    ÃWc˛(ùa “fake” stack. (CopyBits°dONLNd    Êc<oV(ãZused °dONLNd    ÎcVo˛)Tto try for a 64K block, but this has been changed, and it may change again.) If this°dONLNd
  6086. @o<{)(óZ4succeeds, then all is well and the image is copied. °dONLNd
  6087. to){˛)Ì+If the temporary memory traps do not exist,°dONLNd
  6088. †{<ár(£Z=or if CopyBits cannot allocate a 256K buffer, then the image °dONLNd
  6089. ›{rá˛(£êis not copied and CopyBits°dONLNd
  6090. ¯á<ìa(ØZreturns. ◊X◊
  6091. *=Basic QuickDraw Q&As(Ï˙13)
  6092.  of 22ˇÆ◊#ˇ ˇˇˇˇ#◊ 
  6093. IR,Times
  6094. .+6-Macintosh Technical Notes /4/˘
  6095. °dONLNd)ï*CopyBits does not check °dONLNdï)⁄)}Bin the application heap for free memory, at least not for its work°dONLNd[)5a(Q6buffer. For its °dONLNdk)a5⁄)INwork buffer it will only use the stack, and after that it resorts to temporary°dONLNd∫5Aû(]6memory, if available. There °dONLNd÷5ûA⁄)Ü?are some circumstances that may cause memory allocations in the°dONLNdAM{(i6Japplication heap, but this memory is not used for CopyBits’s image buffer.°dONLNdaYeÑ*NAlso, please note that the implementation of CopyBits is subject to change in °dONLNdØYÑe⁄(Å¢future versions of°dONLNd¬eqR(ç6
  6096. QuickDraw.
  6097. °dONLNdÕâòã*'2PICTs with PostScript PICT comments and memory use
  6098. °dONLNdò§>* Written:°dONLNd    òd§à)L1/10/92°dONLNd§∞](Ã6Last reviewed:°dONLNd §d∞à)L2/17/92°dONLNd(º»K(‰6    Why does °dONLNd1ºK»⁄)3Jmy PICT (including dotted lines) use so much memory when drawn in MacDraw,°dONLNd|»‘ø(6Sand even more when drawn in SuperPaint? Do they include PicComments for PostScript?°dONLNd–‘‡** ___°dONLNd‘ϯ¶*OYour guess that it has to do with PicComments is quite right; both MacDraw and °dONLNd#϶¯⁄(ƒ
  6099. SuperPaint°dONLNd.¯⁄( 6'include a PostScript representation of °dONLNdU¯⁄⁄)¬0the dotted (dashed) lines and some other graphic°dONLNdÜä(,6operations in the PICT, °dONLNdûä⁄)rBtogether with the QuickDraw commands. During printing, this allows°dONLNd·d(86the LaserWriter °dONLNdÒd⁄)LQdriver to take advantage of specific PostScript capabilities that are unavailable°dONLNdC(ˆ(D6/in QuickDraw, like primitives for dashed lines.°dONLNds4@ã*JOn the other hand, the PostScript representation for dashed lines is much °dONLNdΩ4ã@⁄(\©shorter than the°dONLNdŒ@L`(h6?QuickDraw representation, which requires a (long, very long …) °dONLNd
  6100. @`L⁄(h~sequence of “ShortLine”°dONLNd%LXõ(t6opcodes. So, another piece °dONLNd@LõX⁄)ÉBof explanation for the large PICT size basically is that QuickDraw°dONLNdÉXdW(Ä6Edoes not have facilities to describe dotted lines in an economic way.°dONLNd…p|∂*YSuperPaint also includes a copy of a proprietary dictionary, which adds substantially to °dONLNd"p∂|⁄(ò‘the size°dONLNd+|ày(§6Gof a PICT. On the other hand, the code that resides in that dictionary °dONLNdr|yà⁄(§ómakes the picture’s°dONLNdÜàî(∞68PostScript representation that much better. Ultimately, °dONLNdæàî⁄(∞9"WYSIWYG is the goal, and sometimes°dONLNd·î†z(º6Pit takes a little extra code to make that happen. (Incidentally, the PostScript °dONLNd1îz†⁄(ºòdictionary contained°dONLNdF†¨r(»6Fin pictures created by older versions of SuperPaint makes assumptions °dONLNdå†r¨⁄(»êabout the contents of°dONLNd¢¨∏(‘6.the LaserPrep file which are not true for the °dONLNd–¨∏⁄)Î*recent versions of the LaserWriter driver.°dONLNd˚∏ƒe(‡6FDocuments containing such pictures will not print correctly any more.)°dONLNdB–‹a*DTo determine the primitives that define other nonstandard QuickDraw °dONLNdÜ–a‹⁄(¯objects found in drawing°dONLNdü‹Ë#(62applications, you can use MPW’s DeRez function or °dONLNd—‹#Ë⁄(A%a third-party utility such as Palomar°dONLNd˜ËÙ
  6101. (60Software’s PICT Detective on the resource PICT. °dONLNd    'Ë
  6102. Ù⁄)ı)These tools will provide the opcodes that°dONLNd    QÙg(6define the PICT.
  6103. °dONLNd    b'û*'8Inside Macintosh Vol. V PICT opcode size should be fixed
  6104. °dONLNd    õ'3>* Written:°dONLNd    §'d3à)L1/22/92°dONLNd    ¨3?]([6Last reviewed:°dONLNd    ª3d?à)L2/28/92°dONLNd    √KWi(s6EThe definition of PICT version 2 on pages 92-105 of Inside Macintosh °dONLNd
  6105. KiW⁄(sáVolume V says that the°dONLNd
  6106. Wc¬(6#data size of the opcodes $001A and °dONLNd
  6107. BW¬c⁄)™9$001B is variable, but also that the data is an RGBColor.°dONLNd
  6108. |co
  6109. (ã61This is confusing, since the size of an RGBColor °dONLNd
  6110. ≠c
  6111. o⁄)ı(is fixed at six bytes. How can these two°dONLNd
  6112. ÷o{ı(ó6.opcodes vary in the amount of associated data?°dONLNd {á** ___°dONLNd     ìü¥*ZSeems like you’ve run into a cut/paste problem. All the opcodes that refer to table 4 are °dONLNd cì¥ü⁄(ª“new for°dONLNd kü´((«64Color QuickDraw. Also, most of them are variable in °dONLNd üü(´⁄(«F"length, so the author simply had a ◊4◊˘
  6113. (Ï614)
  6114.  of 22(ÏñBasic QuickDraw Q&Asˇp◊#ˇ ˇˇˇˇ#◊ 
  6115. IR,Times
  6116. .+Z-Developer Support Center(-Ê October 1992 /X/
  6117. °dONLNd<)    (EZ(standard notation for anything that was °dONLNd(    )˛)Õ.explained further in table 4 (page V-103). The°dONLNdW)<5œ(QZinformation contained in table °dONLNdv)œ5˛)ì?4 is, in fact, accurate. The size information of several of the°dONLNd∂5<A¿(]ZRopcodes listed is not variable even though the preceding pages told you they were.°dONLNd    M<Y>*9All you gotta do is believe table 4 and you will be fine.
  6118. °dONLNdCq<Äã*'1Code for filling an area fully bounded by polygon
  6119. °dONLNduÄ<åb* Written:°dONLNd~Äàå¨)L2/21/92°dONLNdÜå<òÅ(¥ZLast reviewed:°dONLNdïåàò¨)L6/11/92°dONLNdù§<∞(ÃZ]Currently, when a polygon is filled, an even-odd rule is applied to determine which areas of °dONLNd˙§∞˛(Ãthe°dONLNd˛∞<ºâ(ÿZHpolygon are to be filled. For our application, we also need to fill all °dONLNdF∞âº˛(ÿßthe areas of the defined°dONLNd_º<»O(‰Z;polygon. Is there a relatively easy way to accomplish this?°dONLNdõ»<‘N* ___°dONLNdü‡<Ï≥*There are many different °dONLNd∏‡≥Ï˛)wAways to fill polygons, as you may know. If you do not want to use°dONLNd˙Ï<¯2(Z3QuickDraw’s standard FillPoly routine, you’ll have °dONLNd-Ï2¯˛)ˆ(to create your own. The following sample°dONLNdV¯<Û( Zaillustrates one technique that might be used to fill the area fully bounded by a polygon. It can °dONLNd∑¯Û˛( be°dONLNd∫<ù(,ZKdropped right into the traffic light sample (sample.p) that ships with MPW °dONLNdù˛(,ªas a replacement for°dONLNd<ø(8ZOits DrawWindow procedure. The green star is drawn using FillPoly and the black °dONLNdiø˛(8›
  6120. star is drawn°dONLNdw<(d(DZ=using my filling technique that uses an offscreen bitmap and °dONLNd¥d(˛(DÇ calcMask to fill in the poly the°dONLNd’(<4ì(PZdesired way, then °dONLNdÁ(ì4˛)WJCopyBits to transfer it to the onscreen port. The drawbacks of this method°dONLNd24<@W(\ZBare that it is not as fast as writing a specialized poly routine; °dONLNdt4W@˛(\u&the benefits are that it’s small, fast°dONLNdõ@<Lö(hZHenough for most operations, and can be used for more than just polygons.,
  6121. Courier
  6122.     °dONLNd‰X<ci*    {$S Main}°dONLNdÓb<m*
  6123. (PROCEDURE DrawWindow(window: WindowPtr);°dONLNdv<ÅÕ*var        MyPoly:PolyHandle;°dONLNd5Ä<ãπ*
  6124.         MyRgn :RgnHandle;°dONLNdOä<ï◊*
  6125.         OffPort,OnPort:GrafPtr;°dONLNdoû<©O*7    Function    CreateOffport(VAR newOffscreen:grafPtr;°dONLNd®®<≥Ø*
  6126. inBounds:Rect):Boolean;°dONLNd¿º<«*$    var    SavePort,NewPort:Grafptr;°dONLNd–<€i*        begin°dONLNdÔ⁄<Âæ*
  6127.         GetPort(SavePort);°dONLNd
  6128. ‰<Ô;*
  6129. 3        NewPort:=GrafPtr(NewPtr(sizeof(grafport)));°dONLNd>Ó<˘ı*
  6130. %        If MemError<>noErr then Begin°dONLNdd¯<·*
  6131. !            CreateOffport:=false;°dONLNdÜ<
  6132. ‹*
  6133.              EXIT(CreateOffport);°dONLNdß <x*
  6134.         END; ◊X◊
  6135. *πBasic QuickDraw Q&As(Ï˙15)
  6136.  of 22ˇ
  6137. >◊#ˇ ˇˇˇˇ#◊ 
  6138. IR,Times
  6139. .+6-Macintosh Technical Notes /4/˘,
  6140. Courier
  6141.     °dONLNd'2ö*!        OpenPort(newPort);°dONLNd1<Æ*
  6142.         With newPort^ do begin°dONLNd:;F∏*
  6143.              portRect :=Inbounds;°dONLNd[EP÷*
  6144. &            RectRgn(ClipRgn,inBounds);°dONLNdÇOZ÷*
  6145. &            RectRgn(visRgn, inBounds);°dONLNd©YdT*
  6146.         End;°dONLNdæmx€*'        With newPort^.PortBits DO BEGIN°dONLNdÊwÇ©*
  6147.             Bounds:=Inbounds;°dONLNdÅåq*
  6148. E            rowBytes:= ((inBounds.right-inBounds.Left+15) DIV 16) *2;°dONLNdJãñ÷*
  6149. &            baseAddr:= NewPtr(rowBytes°dONLNdrï†q*
  6150. E                            * LONGINT(inBounds.Bottom-inBounds.Top));°dONLNd∏ü™T*
  6151.         End;°dONLNd≈©¥÷*
  6152. &        If MemError <>noErr THEN BEGIN°dONLNdÏ≥æÆ*
  6153.             SetPort(SavePort);°dONLNd Ω»≥*
  6154.             ClosePort(newPort);°dONLNd+«“Ã*
  6155. $            DisposPtr(ptr(newPort));°dONLNdP—‹Ω*
  6156. !            CreateOffport:=false;°dONLNdr€ÊY*
  6157.  
  6158.           END°dONLNdÄÂw*
  6159.         ELSE  BEGIN°dONLNdîÔ˙∏*
  6160.              EraseRect(inBounds);°dONLNdµ˘«*
  6161. #            newOffscreen :=newPort;°dONLNdŸÆ*
  6162.             setPort(SavePort);°dONLNd¯
  6163. ∏*
  6164.              CreateOffPort:=true;°dONLNd"T*
  6165.         end;°dONLNd&!,@*
  6166.     end;°dONLNd35@*4    Procedure    KillOffPort(oldOffscreen :GrafPtr);°dONLNdh?JE*
  6167.         Begin°dONLNdrIT∏*
  6168.          ClosePort(oldOffscreen);°dONLNdìS^*
  6169. 3        DisposPtr(OldOffscreen^.portBits.baseAddr);°dONLNd«]h—*
  6170. %        DisposPtr(ptr(OldOffScreen));°dONLNdÌgr@*
  6171.     End;°dONLNdˆ{Ü1*BEGIN°dONLNd¸Öêè*
  6172. K    If NOT (CreateOffPort(offPort,window^.portRect)) THEN Exit(DrawWindow);°dONLNdHèöä*
  6173. J    If NOT (CreateOffPort(onPort,window^.portRect)) THEN Exit(DrawWindow);°dONLNdó£Æ|*    SetPort(window);°dONLNd¨∑¬r*    MyRgn:=NewRgn;°dONLNdø¡ÃT*
  6174.     OpenRgn;°dONLNdÃÀ÷Ü*
  6175.         MoveTo(10,25);°dONLNd„’‡Ü*
  6176.         Lineto(70,25);°dONLNd˙flÍÜ*
  6177.         Lineto(15,70);°dONLNdÈÙÜ*
  6178.         Lineto(40,10);°dONLNd(Û˛Ü*
  6179.         Lineto(65,70);°dONLNd?˝Ü*
  6180.         Lineto(10,25);°dONLNdV|*
  6181.     CloseRgn(MyRgn);°dONLNdk&Å*    MyPoly:=OpenPoly;°dONLNdÅ%0Ü*
  6182.         MoveTo(10,25);°dONLNdò/:Ü*
  6183.         Lineto(70,25);°dONLNdØ9DÜ*
  6184.         Lineto(15,70);°dONLNdΔCNÜ*
  6185.         Lineto(40,10);°dONLNd›MXÜ*
  6186.         Lineto(65,70);°dONLNdÙWbÜ*
  6187.         Lineto(10,25);°dONLNd al^*
  6188.     ClosePoly;°dONLNdkv©*
  6189.     OffsetPoly(MyPoly,0,100);°dONLNd8äÅ*    SetPort(OffPort);°dONLNdNâîÜ*
  6190.     FramePoly(MyPoly);°dONLNdeìûÂ*
  6191. )    { Now "Fill the poly" the right way }°dONLNdèù®v*
  6192. F    CalcMask(    Offport^.portBits.BaseAddr,OnPort^.portBits.BaseAddr, ◊4◊˘
  6193. *(16)
  6194.  of 22(ÏñBasic QuickDraw Q&Asˇ&◊#ˇ ˇˇˇˇ#◊ 
  6195. IR,Times
  6196. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6197. Courier
  6198.     °dONLNd<(ö(DZF                OffPort^.portBits.RowBytes, OnPort^.portBits.RowBytes,°dONLNdG'<2r*
  6199. >                OffPort^.portRect.bottom-OnPort^.portRect.Top,°dONLNdÜ1<<6*
  6200. 2                OffPort^.portBits.RowBytes DIV 2);°dONLNdπ;<F†*
  6201.     SetPort(OnPort);°dONLNdŒE<P†*
  6202.     SetPort(Window);°dONLNd‰Y<d†*    If gStopped then°dONLNd˘c<nT*
  6203. 8        CopyBits(    OnPort^.portBits, Window^.portBits,°dONLNd2m<xï*
  6204. E                    OnPort^.portRect, Window^.portRect, srcCopy, NIL)°dONLNdxw<Çd*
  6205.     ELSE°dONLNdÅÅ<åY*
  6206. 9        CopyBits(    OffPort^.portBits, Window^.portBits,°dONLNdªã<ñü*
  6207. G                    OffPort^.portRect, Window^.portRect, srcCopy, NIL);°dONLNdü<™†*    IF gStopped THEN°dONLNd©<¥s*
  6208.       begin°dONLNd$≥<æ“*
  6209.         ForeColor(greenColor);°dONLNdCΩ<»¥*
  6210.         FrameRgn(MyRgn);°dONLNd\«<“i*
  6211.           end°dONLNdf—<‹d*
  6212.     ELSE°dONLNdo€<Ês*
  6213.       begin°dONLNd{Â<“*
  6214.         ForeColor(greenColor);°dONLNdöÔ<˙¥*
  6215.         PaintRgn(MyRgn);°dONLNd≥˘<n*
  6216.  
  6217.       end;°dONLNdæ<æ*
  6218.     ForeColor(blackColor);°dONLNdŸ
  6219. <™*
  6220.     DisposeRgn(MyRgn);°dONLNd<"•*
  6221.     KillPoly(MyPoly);°dONLNd!<,π*
  6222.     KillOffPort(Offport);°dONLNd +<6¥*
  6223.     KillOffPort(OnPort);°dONLNd95<@ë*
  6224. END; {DrawWindow}
  6225. °dONLNdKW<f«*&7Use crsrNew flag to unobscure cursor without mouse move
  6226. °dONLNdÉf<rb* Written:°dONLNdåfàr¶)L3/3/92°dONLNdìr<~Å(öZLast reviewed:°dONLNd¢rà~¨)L6/11/92°dONLNd™ä<ñU(≤Z4The Macintosh QuickDraw routine ObscureCursor hides °dONLNdfiäUñ˛(≤s"the cursor until the next time the°dONLNdñ<¢Ó(æZXmouse is moved but isn’t affected by HideCursor or ShowCursor. Our application needs to °dONLNdYñÓ¢˛(æ use°dONLNd]¢<ÆÓ( ZZObscureCursor while the user is typing but needs the cursor to be visible after no typing °dONLNd∑¢ÓÆ˛(  has°dONLNdªÆ<∫(÷Z'occurred for a short period. How do we °dONLNd‚Æ∫˛)»0“undo” ObscureCursor, since we can’t rely on the°dONLNd∫<ΔØ(‚Zuser moving the mouse?°dONLNd*Δ<“N* ___°dONLNd.fi<͢*%The only way to unobscure the cursor °dONLNdSfi˘Í˛)Ω2is to convince the system that the mouse has moved°dONLNdÜÍ<ˆ/(Z5again. There is no real good way to do this via tool °dONLNdªÍ/ˆ˛)Û,calls, so you are going to have to do it the°dONLNdˈ<T(Zhard °dONLNd̈T˛)Uway and simply update the low-memory cursor information to tell the system the cursor°dONLNdC<z(*ZBmoved (even though you do not need to update the actual position).°dONLNdÜ<&Œ*OTo tell the system the cursor has changed location, you simply set the crsrNew °dONLNd’Œ&˛(BÏ
  6227. flag to 1;°dONLNd‡&<2_(NZ9crsrNew is a byte located at $08CE. When the system sees °dONLNd&_2˛(N}!this byte is 1 it will assume the°dONLNd;2<>è(ZZGcursor has moved, unobscure it, redraw at the appropriate place (where °dONLNdÇ2è>˛(Z≠it was all along...) and°dONLNdõ><J˛(fZ]reset crsrNew waiting for the mouse to move again, as in the following C and Pascal examples:
  6228.     °dONLNd˘V<a™*/* the C version... */°dONLNd`<kÕ*
  6229. void UnObscureCursor ( void )°dONLNd.j<uA*
  6230. {°dONLNd0t<™*
  6231.    *(char *)0x8CE = 1;°dONLNdG~<âA*
  6232. } ◊X◊
  6233. *GBasic QuickDraw Q&As(Ï˙17)
  6234.  of 22ˇ
  6235. î◊#ˇ ˇˇˇˇ#◊ 
  6236. IR,Times
  6237. .+6-Macintosh Technical Notes /4/˘,
  6238. Courier
  6239.     °dONLNd'2ê*!(* the pascal version *)°dONLNd1<ö*
  6240. Procedure UnObscureCursor;°dONLNd4EP1*begin°dONLNd:OZr*
  6241.    ptr($08CE)^:=1;°dONLNdMYd,*
  6242. end;
  6243. °dONLNdRo{3*;This will do what you want in a short, easy-to-use package.
  6244. °dONLNdéì¢
  6245. *'!Macintosh QuickDraw region quirks
  6246. °dONLNd∞¢Æ>* Written:°dONLNdπ¢dÆÇ)L1/1/90°dONLNd¿Æ∫](÷6Last reviewed:°dONLNdœÆd∫é)L11/21/90°dONLNdÿΔ“,(Ó6I’m °dONLNd‹Δ,“⁄)Sworking with regions, and I’m having problems with Macintosh QuickDraw trashing the°dONLNd0“fi1(˙68heap and crashing, even though my regions are under 32K.°dONLNdifiÍ** ___°dONLNdmˆï*There are some quirks in °dONLNd܈ï÷)}<the current version of QuickDraw. Here are some the commonly°dONLNd¬ˆ÷⁄(Ù-°dONLNd√É(*6encountered problems:°dONLNdŸ&ö*1. When doing operations °dONLNdÚö&⁄)Ç;which use more than one region, sduch as UnionRgn, DiffRgn,°dONLNd.&28(N67XorRgn, or SectRgn, the sum of the sizes of the source °dONLNde&82a(NVregions °dONLNdm&a2ª))must be less than°dONLNd~&ª2⁄)Z 32K,°dONLNdÑ2>Í(Z6/regardless of the size of the resulting region.°dONLNd¥JVO*D2. FrameRgn will fail if it tries to frame a region bigger than 16K.°dONLNd˘bn¥*#3. If CloseRgn fails, the internal °dONLNdb¥n⁄)ú>region data is already corrupt; there is nothing you can do to°dONLNd[nzπ(ñ6]recover. CloseRgn will also fail if there isn’t at least a 32K block of free space available.°dONLNdπÜí°*Here are some workarounds:°dONLNd‘û™É*1. Keep regions small °dONLNdÍûÉ™⁄)kFand not too complex. Keep track of the sizes of all regions so you can°dONLNd1™∂k(“6Icheck the SUM of the sizes before calling a routine that has a 32K limit.°dONLNd{¬Œ¨*V2. Keep 32K free, or allocate a 32K block and release it just before calling CloseRgn.°dONLNd“⁄Ê”*[Apple is working on these problems and expects to fix them in future versions of QuickDraw.
  6247. °dONLNd.˛
  6248. V*',How to get Macintosh QuickDraw arc endpoints
  6249. °dONLNd[
  6250. >* Written:°dONLNdd
  6251. dÇ)L1/1/90°dONLNdk%](A6Last reviewed:°dONLNdzd%é)L11/21/90°dONLNdÉ1=Í(Y6*Is there a way to obtain the endpoints of °dONLNd≠1Í=⁄)“+an arc drawn by the Macintosh QuickDraw arc°dONLNdŸ=Ifl(e6(routines, such as FrameArc and PaintArc?°dONLNdIU** ___°dONLNdamó*OGiven a rectangle R which frames the arc you wish to draw, convert your angles °dONLNdUaóm⁄(âµto an absolute°dONLNddmyö(ï6Qcoordinate system, where three o’clock is 0 degrees and 12 o’clock is 90 degrees.°dONLNd∂ÖëE*    Now, let:
  6252.     °dONLNd¿ù®÷*&    x = .5 (+ or -) (R.right - R.left) ◊4◊˘
  6253. *(18)
  6254.  of 22(ÏñBasic QuickDraw Q&Asˇ
  6255. d◊#ˇ ˇˇˇˇ#◊ 
  6256. IR,Times
  6257. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6258. Courier
  6259.     °dONLNd<(˙(DZ&    y = .5 (+ or -) (R.bottom - R.top)
  6260. °dONLNd'3<?*-The endpoint of the curve will be defined by:
  6261.     °dONLNdUK<Vı*%    EndPoint.h = x (+ or -) cos(ang);°dONLNd{U<`ı*
  6262. %    EndPoint.v = y (+ or -) sin(ang);
  6263. °dONLNd°k<w˝*+h & v are relative to center of rectangle R°dONLNdÕÉ<è’*This calculates only the upper °dONLNdÏÉ’è˛)ô;endpoint of the arc, but you can easily calculate the other°dONLNd(è<õ„(∑Z endpoint using the same formula °dONLNdHè„õ˛)ß9by calculating the absolute angle for the start point and°dONLNdÇõ<ßΩ(√Zapplying the same formula.°dONLNdù≥<øô*KHere is a subroutine which illustrates the algorithm, in LightSpeed Pascal:
  6264.     °dONLNdÈÀ<÷Å*A{ DrawCurve: draw an arc from 0 degrees until the point defined }°dONLNd+’<‡J*
  6265. 6{ by 'angle'. At that point draw a 4 by 4 crosshair. }°dONLNdzÈ<Ù@*4procedure DrawCurve (frame : Rect; angle : integer);°dONLNdØ˝<K*var°dONLNd≥<ë*
  6266.   x, y : integer;°dONLNd≈<†*
  6267.   xr, yr : extended;°dONLNd⁄<&ë*
  6268.   rad : extended;°dONLNdÏ/<:U*begin°dONLNdÚC<N“*  { Convert angle to radians }°dONLNdM<X˙*
  6269. &  rad := (90 - angle) / 180 * 3.14159;°dONLNd8a<l†*  { Find end point }°dONLNdMk<v6*
  6270. 2  xr := (frame.right - frame.left) * cos(rad) / 2;°dONLNdÄu<Ä6*
  6271. 2  yr := (frame.bottom - frame.top) * sin(rad) / 2;°dONLNd≥<äT*
  6272. 8  x := (frame.right + frame.left) / 2 + Num2Integer(xr);°dONLNdÏâ<îT*
  6273. 8  y := (frame.bottom + frame.top) / 2 + Num2Integer(yr);°dONLNd%ù<®†*  { Draw crosshair }°dONLNd:ß<≤õ*
  6274.   MoveTo(x - 4, y);°dONLNdN±<ºõ*
  6275.   LineTo(x + 4, y);°dONLNdbª<Δõ*
  6276.   MoveTo(x, y - 4);°dONLNdv≈<–õ*
  6277.   LineTo(x, y + 4);°dONLNdäŸ<‰Ç*  { Draw arc }°dONLNdô„<Ó»*
  6278.   FrameArc(frame, 0, angle);°dONLNd∂Ì<¯P*
  6279. end;
  6280. °dONLNdª<c*&*Macintosh CopyBits no longer limited to 3K
  6281. °dONLNdÊ<*b* Written:°dONLNdÔà*¶)L5/3/89°dONLNdˆ*<6Å(RZLast reviewed:°dONLNd*à6≤)L11/21/90°dONLNdB<NÙ(jZ_Inside Macintosh Volume I (page 188) says there is a 3K limit for CopyBits. Is this still true?°dONLNdnN<ZN* ___°dONLNdrf<rÜ*HThe CopyBits limit is obsolete; there is no longer a 3K limit. The limit°dONLNdªr<~Ü* Bdepends on the amount of RAM in your Macintosh. CopyBits tries to °dONLNd˝rÜ~˛(ö§use the stack to do all of°dONLNd~<äé(¶ZHthe copying. In most cases CopyBits is able to copy entire screen shots °dONLNd`~éä˛(¶¨at one time. You might°dONLNdwä<ñ°(≤Zrun into problems if °dONLNdåä°ñ˛)eByou don’t have enough stack to hold two times the rowBytes of your°dONLNdœñ<¢≥(æZPsource, but even in this case CopyBits will attempt to find the memory it needs. ◊X◊
  6282. *.Basic QuickDraw Q&As(Ï˙19)
  6283.  of 22ˇ◊#ˇ ˇˇˇˇ#◊ 
  6284. IR,Times
  6285. .+6-Macintosh Technical Notes /4/˘
  6286. °dONLNd)59*$X-Ref:°dONLNd5A * #Inside Macintosh Volume I, page 188
  6287. °dONLNd+Yhº*';Why grafPort’s clipRgn should be changed before OpenPicture
  6288. °dONLNdght>* Written:°dONLNdphdtà)L11/1/90°dONLNdxtÄ](ú6Last reviewed:°dONLNdátdÄé)L12/19/90°dONLNdêåò+(¥6On °dONLNdìå+ò⁄)Qpage 189 of Inside Macintosh, Volume I, in the QuickDraw chapter’s description of°dONLNdÂò§–(¿6&OpenPicture, is the following warning:°dONLNd ∞ºÇ*P“A grafPort's clipRgn is initialized to an arbitrarily large region. You should °dONLNd\∞Ǻ⁄(ÿ†always change the°dONLNdnº» (‰6YclipRgn to a smaller region before calling OpenPicture, or no drawing may occur when you °dONLNd«º »⁄(‰Ëcall°dONLNdû‘\(6
  6289. DrawPicture.”°dONLNd⁄‡Ï—*(The “arbitrarily large” clipping region °dONLNd‡—Ï⁄)π4rectangle is set to -32767,- 32767,32767,32767 (top,°dONLNd7ϯ“(6)left, bottom, right) for new ports. This °dONLNd`Ï“¯⁄)∫;is the largest rectangle possible. If this is not a "valid"°dONLNdú¯n( 6clipping rectangle °dONLNdدn⁄)VOfor pictures, what is? Is there some specific limit to the size of the clipping°dONLNdˇã(,6Prectangle? Does it depend on either available memory or the size of the picture?°dONLNdP** ___°dONLNdT(4¥*ZInside Macintosh ’s warning is based on truth but it’s incomplete. It didn’t actually say °dONLNdÆ(¥4⁄(P“    that this°dONLNd∏4@=(\6Crectangle is invalid as a clipping region, because this is in fact °dONLNd˚4=@⁄(\["a perfectly valid clipping region.°dONLNd@Là(h6FBut, you could run into problems if you use this as a clipping region °dONLNdd@àL⁄(h¶when creating a°dONLNdtLX˛(t62QuickDraw picture. It’s not a matter of available °dONLNd¶L˛X⁄)Ê.memory or size; it’s a simple matter of 16-bit°dONLNd’Xd‘(Ä6&signed integer overflow and underflow.°dONLNd¸p|9*When °dONLNdp9|⁄)!Syou open a picture, the current clip region is recorded in the picture (this wasn’t°dONLNdU|ày(§6Enecessarily true in some early versions of QuickDraw). When you draw °dONLNdö|yà⁄(§óthe resulting picture°dONLNd∞àîr(∞6using the picture’s °dONLNdƒàrî⁄)ZJpicFrame as the destination rectangle, there won’t be any problems. But if°dONLNdî†A(º6Ayou use a destination rectangle that’s larger than the picFrame, °dONLNdPîA†⁄(º_QuickDraw scales everything in°dONLNdo†¨L(»6 the picture °dONLNd{†L¨⁄)4Uproportionately, including the clip region. If you allowed the default clip region to°dONLNd—¨∏(‘68be recorded into the picture, then its rgnBBox, already °dONLNd    ¨∏⁄(‘:'as large as possible, will be made even°dONLNd1∏ƒA(‡6:larger. That means that the -32767 coordinates might wrap °dONLNdk∏Aƒ⁄(‡_around to the positive number°dONLNd⃖§(Ï6Qrange, and the 32767 coordinates might wrap around to the negative number range. °dONLNd⁄ƒ§–⁄(Ϭ This leaves°dONLNdÊ–‹&(¯69you with an empty clip region. Nothing at all gets drawn °dONLNd–&‹⁄(¯D&when the current port’s clip region is°dONLNdF‹Ë9(6empty.°dONLNdMÙŸ*(If the destination rectangle is smaller °dONLNduÙŸ⁄)¡/than the picture’s picFrame, you won’t have any°dONLNd• ´((6Uproblems because the default clip region will be made smaller, and that’s no problem.°dONLNd˚$∫*UThis is why Inside Macintosh suggests that you make the clip region smaller than the °dONLNd    P∫$⁄(@ÿdefault°dONLNd    X$0µ(L6Sclip region before opening a picture. By doing this, you’re almost guaranteed that °dONLNd    ´$µ0⁄(L”the clip°dONLNd    ¥0<¨(X6region won’t get scaled to the °dONLNd    ”0¨<⁄)î=point that it turns inside out. What size should you make it?°dONLNd
  6290. <H§(d6SSmall enough so that the risk of the clip region’s coordinates being scaled out of °dONLNd
  6291. d<§H⁄(d¬    QuickDraw°dONLNd
  6292. nHTê(p6Scoordinate space is minimal. I usually just set the clip region to the picFrame of °dONLNd
  6293. ¡HêT⁄(pÆthe picture. It’s°dONLNd
  6294. ”T`ô(|6hard to go wrong this way. ◊4◊˘
  6295. *p20)
  6296.  of 22(ÏñBasic QuickDraw Q&AsˇÚ◊#ˇ ˇˇˇˇ#◊ 
  6297. IR,Times
  6298. .+Z-Developer Support Center(-Ê October 1992 /X/
  6299. °dONLNd)<8}(TZ+Macintosh CalcMask and CopyMask code sample
  6300. °dONLNd,8<Db* Written:°dONLNd58àD¨)L2/27/92°dONLNd=D<PÅ(lZLast reviewed:°dONLNdLDàP¨)L5/21/92°dONLNdT\<hÙ(ÑZ(I can’t get the black-and-white version °dONLNd|\Ùh˛)∏5of my lasso-type tool to work correctly with CalcMask°dONLNd≤h<tŸ(êZPand CopyMask. With CalcCMask it seems to work fine. What could I be doing wrong?°dONLNdt<ÄN* ___°dONLNdå<òs*>CalcMask and CalcCMask are similar in that they both generate °dONLNdEåsò˛(¥ëa 1-bit mask given a source°dONLNdaò<§,(¿Z-bitmap. With CalcCMask, though, a pixMap can °dONLNdéò,§˛)*be used in place of the source bitmap; the°dONLNdπ§<∞(ÃZ(seedRGB determines which color sets the °dONLNd·§∞˛)»2bits in the mask image. An easy mistake to make is°dONLNd∞<º=(ÿZ7to forget that CalcCMask accepts a pointer to a bitmap °dONLNdK∞=º˛(ÿ['data structure while CalcMask expects a°dONLNdsº<»ü(‰Zpointer to the actual °dONLNdâºü»˛)cBbit image. And unlike CalcCMask, which uses bounding Rects for the°dONLNdû<‘ı(ZPimage’s dimensions, CalcMask uses the bitmap’s rowBytes and pixel image offsets °dONLNd»ı‘˛(to°dONLNd‘<‡Ã(¸ZUdetermine the bounding Rects for the image. A typical call to these routines would be,
  6301. Courier
  6302.     °dONLNduÏ<˜¥*    BitMap source, mask;°dONLNdéˆ<r*
  6303. >    CalcMask (source.baseAddr, mask.baseAddr, source.rowBytes,°dONLNdŒ< ê*
  6304. D              mask.rowBytes, source.bounds.bottom-source.bounds.top,°dONLNd
  6305. <Ê*
  6306. "              source.rowBytes>>1);°dONLNd7<Ü*
  6307. B    CalcCMask (&source, &mask, &(*source).bounds, &(*mask).bounds,°dONLNd{<)·*
  6308. !               &seedRGB, nil, 0);
  6309. °dONLNdù4<@.*3One last thing to note when using CalcMask is that °dONLNd–4.@˛)Ú*the width of the image is in words and not°dONLNd˚@<L:(hZ4bytes. To learn more about these routines, see page °dONLNd/@:L˛)˛$24 of Inside Macintosh Volume IV and°dONLNdTL<X–(tZRpage 72 of Inside Macintosh Volume V. Also, the Developer CD Series disc contains °dONLNd¶L–X˛(tÓ    a sample,°dONLNd∞X<d|(ÄZ>CalcCMask&CalcMask, that shows how to use both these routines.
  6310. °dONLNdÔ|<ãí*'-Macintosh QuickDraw LineTo bug and workaround
  6311. °dONLNdã<ób* Written:°dONLNd&ãàó¨)L4/23/92°dONLNd.ó<£Å(øZLast reviewed:°dONLNd=óࣨ)L7/13/92°dONLNdEØ<ª2(◊Z1Our zooming function crashes into flames when we °dONLNdvØ2ª˛)ˆ*pass valid coordinate values to LineTo, as°dONLNd°ª<«¥(„Zin the following example:
  6312.     °dONLNdª”<fi†*    SetPort(myPort);°dONLNd–›<Ë™*
  6313.     MoveTo(154,31619);°dONLNdÁÁ<Ú*
  6314. +    LineTo(74, -31742); (* You are dead! *)
  6315. °dONLNd˝<    )*1What can we do to avoid LineTo crashes like this?°dONLNdE    <N* ___°dONLNdI!<-Δ*The QuickDraw Engineering °dONLNdc!Δ-˛)ä=group is aware of the problem you described. The bug probably°dONLNd°-<9(UZ.is going to be fixed in the next release that °dONLNdœ-9˛)…3includes bug fixes. Given that waiting for a system°dONLNd9<EC(aZ6solution may demand more patience than is reasonable, °dONLNd99CE˛(aa%you may want to consider including in°dONLNd_E<QÖ(mZCyour software some form of workaround that will prevent your users °dONLNd¢EÖQ˛(m£from crashing every time°dONLNdªQ<]R(yZ;an operation takes the software to the limits of QuickDraw.°dONLNd˜i<uŸ*XOne way to approach this problem is to replace the lineProc bottleneck. All you need to °dONLNd    OiŸu˛(ë˜do is to°dONLNd    Xu<Åî(ùZcheck the distance °dONLNd    kuîŞ)XJbetween the current pen position and the line’s end, and when the distance°dONLNd    ∂Å<çÙ(©ZVbecomes too big (let’s say more than 32000) your procedure will call StdLine a couple °dONLNd
  6316. ÅÙç˛(©of°dONLNd
  6317. ç<ôÁ(µZ×, splitting the operation in two. ◊X◊
  6318. *7Basic QuickDraw Q&As(Ï˙21)
  6319.  of 22ˇ ◊#ˇ ˇˇˇˇ#◊ 
  6320. IR,Times
  6321. .+6-Macintosh Technical Notes /4/˘
  6322. °dONLNd)û*Replacing the bottlenecks is °dONLNdû)⁄)Ü@a very straightforward operation (which you are probably already°dONLNd^)5≠(Q6 using) and in most of the cases °dONLNd~)≠5⁄)ïAwill only result in another level of indirection into StdLine but°dONLNd¿5A´(]6that will prevent your program °dONLNdfl5´A⁄)ì=from calling QuickDraw with parameters that are guaranteed to°dONLNdAM\(i6cause crashes.
  6323. °dONLNd,et*'QuickDraw globals at INIT time"Ñ3
  6324. °dONLNdKtÄ>* Written:°dONLNdTtdÄÇ)L6/1/92"ì3 °dONLNd[Äå](®6Last reviewed:°dONLNdjÄdåà)L9/15/92"ü3 "´3 °dONLNdrò§?(¿6@If I call InitGraf before I reference CurrentA5, will CurrentA5 °dONLNd≤ò?§⁄(¿]be valid and can the QuickDraw"∑3 °dONLNd—§∞7(Ã6;globals be referenced off it? The screenBits bounds values °dONLNd §7∞⁄(ÃUseem screwy on some machines."√3 °dONLNd*∞ºS(ÿ6@Does the problem lie with CurrentA5? Should I be referencing A5?"œ3 °dONLNdkº»** ___"€3 "Á3 °dONLNdo‘‡÷*%Here’s the process used by ShowINIT, °dONLNdî‘÷‡⁄)æ3which is remarkably compatible with system software"Û3 °dONLNd»‡ÏQ(6<and other INITs (and it had better be, because it’s used by °dONLNd‡QÏ⁄(omore than half the system"ˇ3 °dONLNdϯ}(6extensions available):" 3 "3 °dONLNd5;*B1. It saves the value in the CurrentA5 global to restore it later."#3 °dONLNdxb* I2. It points the A5 register at 4 bytes of storage for use by the system."/3 °dONLNd¬(.* ;3. It copies the value now in A5 into the CurrentA5 global.";3 °dONLNd˛(4¡* ^4. It calls InitGraf, passing a pointer to the thePort field of a QuickDraw globals structure."G3 °dONLNd]4@§* V5. It opens a port and draws as necessary. [This is where all the functionality goes.]"S3 °dONLNd¥@Læ* '6. After it’s done, it closes its port."_3 °dONLNd‹LX,* >7. It copies the value saved in step (1) into the A5 register."k3 °dONLNdXd3* =8. It copies the restored A5 value into the CurrentA5 global."w3 "É3 °dONLNdYp|d*To summarize, °dONLNdgpd|⁄)LIShowINIT saves the A5, creates and initializes its own A5 world, does its"è3 °dONLNd±|àé(§6Kdrawing, then restores the previous A5 world. For more information on this °dONLNd¸|éà⁄(§¨subject, see the"õ3 °dONLNd
  6325. àî˚(∞6,Macintosh Technical Note “Stand-Alone Code.”"ß3  ◊4◊˘
  6326. (Ï622)
  6327.  of 22(ÏñBasic QuickDraw Q&Asˇ◊#ˇ ˇˇˇˇ#◊†Ç 
  6328. /ZÅ#
  6329.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6330. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6331. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6332. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6333. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6334.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6335. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6336. IR.°dONLNdz<çS(ßZSo Many Bitmaps, So Little Time
  6337. °dONLNd å<õr*Imaging°dONLNd(ågõ˛(∑ÖM.IM.BitMatToRegion
  6338. °dONLNd<ß<≥t(œZ Revised by:°dONLNdHßÑ≥¿)H Rich Collyer°dONLNdUߥ≥˛(œ“
  6339. December 1989°dONLNdc≥<øq(€Z Written by:°dONLNdo≥Ñø¥)H
  6340. Rick Blair°dONLNdz≥Àø˛(€È
  6341. April 1988°dONLNdÖÃ<ÿT(ÙZThis °dONLNdäÃTÿ)%Technical Note discusses the routine ,
  6342. Courier°dONLNdØÀ◊j)¥BitMapToRegion°dONLNdΩÃjÿ˛)b, which converts a bitmap to a°dONLNd‹ÿ<‰Î(ZXregion, and is available in the 32-Bit QuickDraw INIT and from Apple Software Licensing.°dONLNd5‰<Á* Changes since October 1989:°dONLNdP‰Á‡)´2  Added trap definitions for developers using the °dONLNdlj‡˛)˘32-Bit°dONLNdâ<¸í(ZGQuickDraw version of this routine without the correct MPW include file. 'X'°dONLNd—<!á*%GThe following routine is now available to convert a bitmap to a region:
  6343.     °dONLNd-<8r*>FUNCTION BitMapToRegion(region:RgnHandle; bMap:BitMap): OSErr;
  6344. °dONLNdXC<OS*in C:
  6345.     °dONLNd^[<fc*;pascal OSErr BitMapToRegion(RgnHandle region, BitMap bMap);
  6346. °dONLNdöq<}ò*JIf you are using the 32-Bit QuickDraw version of this routine without the °dONLNd‰qò}˛(ô∂correct MPW include°dONLNd¯}<â`(•Z@file, then you need to include one of the following definitions:°dONLNd9ï<°Z*Pascal
  6347.     °dONLNd@≠<∏Å*AFUNCTION BitMapToRegion (region: RgnHandle; bMap: BitMap): OSErr;°dONLNdÇ∑<¬™*
  6348.          INLINE $A8D7;
  6349. °dONLNdôÕ<ŸD*C
  6350.     °dONLNdõÂ<Ü*Bpascal OSErr BitMapToRegion (RgnHandle region, const BitMap *bMap)°dONLNdfiÔ<˙™*
  6351.              = 0xA8D7;
  6352. °dONLNdı<k*Assembly
  6353.     °dONLNd˛<(**_BitMapToRegion        OPWORD        $A8D7
  6354. °dONLNd)4<@á*The region will °dONLNd94á@)K!be built so that all one bits in °dONLNdZ3?5)íbMap°dONLNd^45@˛), are inside the region and all zero bits are°dONLNdã@<Lx(hZoutside of it.°dONLNdöY<e4*3As with all QuickDraw calls which change a region, °dONLNdÕX4dù)¯BitMapToRegion °dONLNd‹YùeΔ)i    requires °dONLNdÂYΔe˛)) you to pass°dONLNdÒf<r(éZ*an existing region (originally created by °dONLNdeq1)ƒ_NewRgn°dONLNd"f1rÅ)1).  If the region °dONLNd4fÅr˛)Pcannot be built due to an°dONLNdNr<~ò(öZJinsufficient heap space or a size greater than 32K, then the routine will °dONLNdòrò~˛(ö∂return an appropriate°dONLNdÆ~<ä—(¶ZUerror code and the region will be empty.  If the region would have exceeded 32K, the °dONLNd~—ä˛(¶Ô
  6355. error will°dONLNdã<óJ(≥Zbe °dONLNdäJñû) rgnTooBigErr°dONLNdãûó√)T (-500). ◊X◊
  6356. (ÏZSo Many Bitmaps, So Little Time(Ï1) of 2ˇ°¿Ù%%DSIDICT:_cv
  6357. currentdict /bu known {bu}if
  6358. userdict /_cv known not{userdict /_cv 30 dict put}if
  6359. _cv begin
  6360. /bdf{bind def}bind def
  6361. currentscreen/cs exch def/ca exch def/cf exch def
  6362. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6363. /ss{//cf //ca //cs setscreen}bdf
  6364. /stg{ss setgray}bdf
  6365. /strgb{ss setrgbcolor}bdf
  6366. /stcmyk{ss cvcmyk}bdf
  6367. /min1{dup 0 eq{pop 1}if}bdf
  6368. end
  6369. currentdict /bn known {bn}if
  6370. †ø¥◊#ˇ ˇˇˇˇ#◊ 
  6371. IR,Times
  6372. .+6-Macintosh Technical Notes /4/˘
  6373. °dONLNd)∞*SThis function is useful for a number of situations where you have (or can produce) °dONLNdS∞)⁄(EŒa bitmap°dONLNd\*6Ä(R6representing an area.  °dONLNds*Ä6¿)h You can use ,
  6374. Courier°dONLNd)¿5ˇ)@    _CalcMask°dONLNdà*ˇ6⁄)?+ to produce such a bitmap.  Once you have a°dONLNd¥7Ce(_6region, you can °dONLNdƒ7eC)M!perform region operations (i.e., °dONLNdÂ6B:)ù_PtInRgn°dONLNdÌ7:CB)8, °dONLNdÔ6BBÅ)    _UnionRgn°dONLNd¯7ÅCó)?, or °dONLNd˝6óB÷)    _InsetRgn°dONLNd7÷C⁄)?)°dONLNdDP8(l6or call °dONLNdC8Oå)  _DragGrayRgn°dONLNdDåPœ)T, for example.°dONLNd+\hY(Ñ6CThis call is part of the 32-Bit QuickDraw INIT ($A8D7).  If you do °dONLNdn\Yh÷(Ñwnot wish to depend on 32°dONLNdÜ\÷h⁄)}-°dONLNdáiu)(ë6Bit °dONLNdãi)u),QuickDraw, then you can obtain a version of °dONLNd∑htj)flBitMapToRegion°dONLNd≈iju⁄)b in MPW object format°dONLNd€uÅ™(ù6Pwhich can be linked into an MPW program, by contacting Apple Software Licensing:°dONLNd/çÑôˇ+lApple Software Licensing°dONLNdKôÑ•* Apple Computer, Inc.,°dONLNdd•ѱ"* 20525 Mariani Avenue, M/S 38-I°dONLNdܱÑΩÔ* Cupertino, CA, 95014°dONLNdûΩÑ…œ* (408) 974-4667°dONLNd∞…Ñ’* AppleLink:  SW.LICENSE°dONLNd«‚Ó(
  6375. 63If you licensed the older version of this routine, °dONLNd˙·ÌM)ˆ    BitMapRgn°dONLNd‚MÓ¨)?, contact Software °dONLNd‚¨Ó⁄)_    Licensing°dONLNd Ó˙(62about receiving an updated version.  We recommend °dONLNdRÓ˙⁄(9&you update your application to use the°dONLNdy˙¥("6 new version as soon as possible.°dONLNdöØ*The new version is now named °dONLNd∑Ø)óBitMapToRegion°dONLNd≈Ø)b# to be consistent with the version °dONLNdËØ⁄)û    in 32-Bit°dONLNdÚ ,“(H6#QuickDraw and the MPW interfaces.  °dONLNd “,)∫
  6376. In addition, °dONLNd"+r)>BitMapToRegion°dONLNd0 r,⁄)b offers new features.°dONLNdG,8v(T6You can now pass °dONLNdX,v8⁄)^Ea one-bit pixelmap which has been coerced to a bitmap.  If you pass a°dONLNdû9E˚(a61pixelmap which is too large, then you will get a °dONLNdœ8˚Dk)„pixmapTooDeepErr°dONLNdfl9kEè)p (-148) °dONLNdÁ9èE⁄)$error.  You can°dONLNd˜FRW(n6also pass the °dONLNdEWQè)?portBits°dONLNd
  6377. FèRä)84 of a window, much like you would do with a call to °dONLNdAEäQ…)˚    _CopyBits°dONLNdJF…RÕ)?.°dONLNdL^j?(Ü6>There is a potential problem with this routine, since MPW 3.1 °dONLNdä^?j⁄(Ü]!include files contain information°dONLNd¨kw◊(ì6%about 32-Bit QuickDraw.  If you want °dONLNd—j◊v9)øBitMapToRegion°dONLNdflk9w=)b °dONLNd‡k=w⁄) to be available on all machines,°dONLNdwÉß(ü6then you must use the object °dONLNdwßÉ⁄)è;file from Software Licensing.  The problem is that when you°dONLNdZÉèí(´6Mcompile your application with MPW 3.1 or later, the 32-Bit QuickDraw version °dONLNdßÉíè⁄(´∞gets preference°dONLNd∑èõê(∑6over the object file.  You °dONLNd“èêõ´)xmust°dONLNd÷è´õˇ) comment out the °dONLNdÁèˇõ⁄)T/routine in the include files if you want to use°dONLNdú®Å(ƒ6the object file.  If you °dONLNd0úÅ®Ì)ionly care about using °dONLNdFõÌßO)lBitMapToRegion°dONLNdTúO®⁄)b on machines running 32-Bit°dONLNdp®¥Ë(–6)QuickDraw, then you need not do anything. ◊4◊˘
  6378. (Ï62) of 2(ÏmSo Many Bitmaps, So Little Timeˇ¢◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  6379. /ZÅ#
  6380.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6381. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6382. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6383. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6384. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6385.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6386. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  6387. IR.°dONLNd{<éó(®Z'A Leading Cause of Color Cursor Cursing
  6388. °dONLNd(ç<úr*Imaging°dONLNd0çÄú˛(∏ûM.IM.ColorCursor
  6389. °dONLNdA®<¥t(–Z Revised by:°dONLNdM®Ñ¥¡)H
  6390. Alan Mimms°dONLNdX®æ¥˛(–‹ October 1989°dONLNde¥<¿q(‹Z Written by:°dONLNdq¥Ñ¿¡)H
  6391. Alan Mimms°dONLNd|¥Õ¿˛(‹Π   June 1989°dONLNdÜÃ<ÿù(ÙZIWorking with color cursors you create from scratch can cause headaches.  °dONLNdœÃùÿ˛(ÙªThis Technical Note°dONLNd„ÿ<‰Ç(Zmay help a bit.°dONLNdÛÂ<Òœ*
  6392. Changes since June 1989:°dONLNd œÒw)ì"  Added a warning about purgeable ,
  6393. Courier°dONLNd-‰w°)®'clut'°dONLNd3°Ғ)*  resources. X°dONLNd?
  6394. <Ò(2Z'If you’re building an application that °dONLNdf
  6395. Ò˛)µ4creates color cursors, you may encounter some quirks°dONLNdõ<"¿(>ZOpresent in Color QuickDraw that manifest themselves in hard-to-understand ways.°dONLNdÎ.<:º*If your cursor is, say, 15 °dONLNd.º:˛)Ä@pixels tall and 9 pixels wide, you might be tempted to use these°dONLNdG;<GÇ(cZvalues for the °dONLNdV:ÇF›)F
  6396. bounds.bottom°dONLNdc;›Gˆ)[ and °dONLNdh:ˆFJ) bounds.right°dONLNdt;JGí)T, respectively, °dONLNdÑ;íG˛)Hin your cursor’s pixel°dONLNdõG<SZ(oZmap.  °dONLNd°GZSz)Don’t°dONLNd¶GzSˇ) .  The problem is that when °dONLNd¬GˇS˛)Ö3the cursor’s image needs to be expanded (i.e., when°dONLNdˆS<_R({Zyou °dONLNd˙SR_˛)Wspecify a two bit-per-pixel cursor and the mouse pointer is on an eight-bit screen) the°dONLNdR_<kâ(àZ _SetCCursor°dONLNd]`âl÷)M trap rounds the °dONLNdn`÷l˛)M=width of the pixel map in such a way that you’ll get only the°dONLNd¨l<xZ(îZspace °dONLNd≤lZx˛)Rrequired for a 15 by 8 pixel map allocated for the expanded cursor data.  When the°dONLNdx<ÑÈ(†Z%cursor’s image is expanded into this °dONLNd*xÈÑ˛)≠8too-small expanded cursor data handle as a 15 by 9 pixel°dONLNdcÑ<ê(¨Z-map, something in your heap will get munched. °dONLNdëú<®˚*The cure is simple.  Make °dONLNd´ú˚®!)øcertain°dONLNd≤ú!®N)& that  °dONLNd∏úN®˛)-you always specify that the°dONLNd‘®<¥œ(—ZpixmapHandle^^.bounds°dONLNdÈ©œµ)ì be 16 by 16. °dONLNd˜©µt)L This will cause °dONLNd®t¥¡)Y _SetCCursor°dONLNd©¡µ˛)M  to properly°dONLNd µ<¡Ω(›Zallocate the expanded data °dONLNd;µΩ¡˛)ÅAarea, and all will be well in the land.  Since the amount of data°dONLNd}¬<Œ_(ÍZdrawn°dONLNdǬ_Œs)# for °dONLNdá¬sŒw)7a cursor is specified by the cursor’s pixel values and °dONLNdæ¡wÕ°(Íï'clut'°dONLNdƒ¬°Œ˛)* resource, trying to°dONLNdŸŒ<⁄ù(ˆZFsave a few bytes by making the bounds rectangle smaller than 16 by 16 °dONLNdŒù⁄˛(ˆªwouldn’t have been°dONLNd2⁄<ʰ(Zvery helpful anyway.°dONLNdGÚ<˛W*;Another potential problem is with the color cursor’s color °dONLNdÇÚW˛˛(u#table.  If you load the color table°dONLNd¶ˇ< W('Zfrom °dONLNd´ˇW a)a °dONLNd≠˛a
  6397. ã)
  6398. 'clut'°dONLNd≥ˇã ‹)* resource using °dONLNd√˛‹
  6399. ")Q
  6400. _GetCTable°dONLNdÕˇ" «)F , you should make sure that the °dONLNdÌ˛«
  6401. Ò)•'clut'°dONLNdÛˇÒ ˛)* is°dONLNd˜ <(3Z,marked non-purgeable while the color cursor °dONLNd# ˛)›/is in use.  If you do not take this precaution,°dONLNdS<$¥(@Zbombs will occur if your °dONLNdl¥#fi)x'clut'°dONLNdrfi$Ü)*$ gets purged at in inopportune time. ◊X◊
  6402. (ÏZ'A Leading Cause of Color Cursor Cursing(Ï1) of 1ˇ°¿Ù%%DSIDICT:_cv
  6403. currentdict /bu known {bu}if
  6404. userdict /_cv known not{userdict /_cv 30 dict put}if
  6405. _cv begin
  6406. /bdf{bind def}bind def
  6407. currentscreen/cs exch def/ca exch def/cf exch def
  6408. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6409. /ss{//cf //ca //cs setscreen}bdf
  6410. /stg{ss setgray}bdf
  6411. /strgb{ss setrgbcolor}bdf
  6412. /stcmyk{ss cvcmyk}bdf
  6413. /min1{dup 0 eq{pop 1}if}bdf
  6414. end
  6415. currentdict /bn known {bn}if
  6416. †ø◊#ˇ ˇˇˇˇ#◊†Ç 
  6417. /ZÅ#
  6418.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6419. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6420. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6421. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6422. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6423.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6424. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6425. IR.°dONLNdn<Å(õZColor Manager Q&As
  6426. °dONLNdÄ<èr*Imaging°dONLNdÄeè˛(´ÉM.IM.ColorMgr.Q&As
  6427. °dONLNd.õ<ßt(√Z Revised by:°dONLNd:õÑߡ)HDeveloper Support Center°dONLNdSõæß˛(√‹ October 1992°dONLNd`ß<≥q(œZ Written by:°dONLNdlßÑ≥ˇ)HDeveloper Support Center°dONLNdÖßæ≥˛(œ‹ October 1990°dONLNdíø<À⁄(ÁZThis Technical Note contains a °dONLNd±ø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÎÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd2À†◊˛(Ûæthe DSC engineers.°dONLNdE◊<„u(ˇZ
  6428. While DSC °dONLNdO◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdú„<Ôq( Z don’t have °dONLNdß„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˘Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdN˚<(#Z,information migrates into reference manuals.°dONLNd{<k*:Q&As are now included with Technical Notes to make access °dONLNdµk˛(;âto technical updates easier for°dONLNd’<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd/+<7\(SZknow °dONLNd4+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNd~7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNd∏O<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  6429. °dONLNdÄ<èç*4.Color Manager search and complement procedures
  6430. °dONLNd6è<õb* Written:°dONLNd?èàõ¨)L10/7/91°dONLNdGõ<ßÅ(√ZLast reviewed:°dONLNdVõàߨ)L11/6/91°dONLNd^≥<øÖ(€Z The AddComp °dONLNdj≥Öø˙)IHcomplement procedure description in Inside Macintosh Volume V, pages 145°dONLNd≤≥˙ø˛(€-°dONLNd≥ø<À
  6431. (ÁZ*147, is vague. The last paragraph on page °dONLNd›ø
  6432. À˛)—-V-146 states, “Complement procedures work the°dONLNd À<◊Q(ÛZ:same as search procedures,” but SearchProc is a function, °dONLNdEÀQ◊˛(Ûo!CompProc is a procedure, and each°dONLNdg◊<„(ˇZYhave a different number of parameters. What else does CompProc need as input and on exit?°dONLNd¡„<ÔN* ___°dONLNd≈˚<‰*CompProc should be declared as °dONLNd‰˚‰˛)®2a Pascal FUNCTION that returns a Boolean. The code°dONLNd<v(/Z?performs a CLR.B for the return value of CompProc, so treat it °dONLNdVv˛(/îlike SearchProc. CompProc°dONLNdp<æ(;ZQonly uses one parameter since its one parameter is a VAR, which means it will be °dONLNd¡æ˛(;‹
  6433. replaced with°dONLNdœ<+’(GZVthe correct complementary color. SearchProc returns an index in its second parameter, °dONLNd%’+˛(GÛwhich is°dONLNd.+<7Ÿ(SZ why it needs a second parameter. ◊X◊
  6434. *ôColor Manager Q&As(Ï1) of 2ˇ°¿Ù%%DSIDICT:_cv
  6435. currentdict /bu known {bu}if
  6436. userdict /_cv known not{userdict /_cv 30 dict put}if
  6437. _cv begin
  6438. /bdf{bind def}bind def
  6439. currentscreen/cs exch def/ca exch def/cf exch def
  6440. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6441. /ss{//cf //ca //cs setscreen}bdf
  6442. /stg{ss setgray}bdf
  6443. /strgb{ss setrgbcolor}bdf
  6444. /stcmyk{ss cvcmyk}bdf
  6445. /min1{dup 0 eq{pop 1}if}bdf
  6446. end
  6447. currentdict /bn known {bn}if
  6448. †ø r◊#ˇ ˇˇˇˇ#◊ 
  6449. IR,Times
  6450. .+6-Macintosh Technical Notes /4/˘
  6451. °dONLNd)8@*'*Using ResEdit to get Apple icon RGB values
  6452. °dONLNd+8D>* Written:°dONLNd48dDÇ)L1/7/92°dONLNd;DP](l6Last reviewed:°dONLNdJDdPÇ)L8/1/92°dONLNdQ\h^(Ñ6=I am trying to find the RGB values for Apple's standard icon °dONLNdé\^h⁄(Ñ|colors. I can’t find this°dONLNd®htF(ê6@information in any documentation. Is this information available?°dONLNdÈtÄ** ___°dONLNdÌåòß*TWhile the RGB values for the standard Apple icon colors (and other standard palette °dONLNdAåßò⁄(¥≈ colors) are°dONLNdMò§fi(¿6)not explicitly documented, they are easy °dONLNdvòfi§⁄)Δ3to obtain with ResEdit 2.1.1. In any resource file,°dONLNd™§∞Û(Ã6.create and open a new 'pltt' resource. Choose °dONLNdÿ§Û∞⁄)€-Load Colors from the pltt menu and pick Apple°dONLNd∞ºø(ÿ6$Icon Colors, and a standard palette °dONLNd*∞øº⁄)ß<will be created. Selecting a color will reveal its component°dONLNdgº»:(‰6values.°dONLNdo‘‡ú*PResEdit 2.1.1 is available on the latest Developer CD Series disc and from APDA.
  6453. °dONLNd¿¯c*'.Macintosh Color Manager versus Palette Manager
  6454. °dONLNdÔ>* Written:°dONLNd¯dÇ)L1/1/90°dONLNdˇ](;6Last reviewed:°dONLNddÇ)L8/1/92°dONLNd+7Z(S6 When should °dONLNd!+Z7⁄)BJthe Macintosh Color Manager be used and when should the Palette Manager be°dONLNdl7C3(_6used?°dONLNdrCO** ___°dONLNdv[gV*CThe Palette Manager is by far the friendlier and more versatile of °dONLNdπ[Vg⁄(Étthe two if your application°dONLNd’gs°(è6Xuses different colors than the default system colors. It provides all the functionality °dONLNd-g°s⁄(èø you need to°dONLNd9så(õ6Ncustomize and animate the colors in your application. You shouldn’t ever need °dONLNdáså⁄(õ™to use the Color°dONLNdòãå(ß6IManager unless you require custom color search and complement functions. °dONLNd·åã⁄(ß™When using the°dONLNdãóñ(≥6PPalette Manager, applications will maintain their respective color environments °dONLNd@ãñó⁄(≥¥safely as they°dONLNdOó£H(ø67move back and forth from foreground to background, and °dONLNdÜóH£⁄(øffrom one screen to another.°dONLNd¢£Ø¨(À6PAccomplishing this with the Color Manager calls is not worth the effort or very °dONLNdÚ£¨Ø⁄(À     safe. For°dONLNd¸ØªŸ(◊6]additional information, see the Palette Manager chapter in Inside Macintosh Volumes V and VI. ◊4◊˘
  6455. (Ï62) of 2(ÏüColor Manager Q&Asˇp◊#ˇ ˇˇˇˇ#◊†Ç 
  6456. /ZÅ#
  6457.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6458. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6459. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6460. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6461. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6462.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6463. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6464. IR.°dONLNdn<Å(õZColor QuickDraw Q&As
  6465. °dONLNdÄ<èr*Imaging°dONLNdÄkè˛(´âM.IM.ColorQD.Q&As
  6466. °dONLNd/õ<ßt(√Z Revised by:°dONLNd;õÑߡ)HDeveloper Support Center°dONLNdTõ¥ß˛(√“
  6467. December 1992°dONLNdbß<≥q(œZ Written by:°dONLNdnßÑ≥ˇ)HDeveloper Support Center°dONLNdáßæ≥˛(œ‹ October 1990°dONLNdîø<À⁄(ÁZThis Technical Note contains a °dONLNd≥ø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÌÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd4À†◊˛(Ûæthe DSC engineers.°dONLNdG◊<„u(ˇZ
  6468. While DSC °dONLNdQ◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdû„<Ôq( Z don’t have °dONLNd©„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˚Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdP˚<(#Z,information migrates into reference manuals.°dONLNd}<k*:Q&As are now included with Technical Notes to make access °dONLNd∑k˛(;âto technical updates easier for°dONLNd◊<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd1+<7\(SZknow °dONLNd6+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNdÄ7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNd∫O<[¨*New Q&As this month:°dONLNdœ[<gV* /Disabling Macintosh Color QuickDraw for testing íXí
  6469. °dONLNdˇå<õâ*4/Disabling Macintosh Color QuickDraw for testing
  6470. °dONLNd/õ<ßx*
  6471. Date written:°dONLNd=õàߨ)L9/14/92°dONLNdEß<≥Å(œZLast reviewed:°dONLNdTßà≥¨)L11/1/92°dONLNd\ø<À5(ÁZ3Is there an easy way to disable Color QuickDraw on °dONLNdèø5À˛)˘*a Macintosh? I want to do this for testing°dONLNd∫À<◊fi(ÛZVour application, to make sure it works correctly on a machine without Color QuickDraw.°dONLNd◊<„N* ___°dONLNdÔ<˚Ø*MThere’s no easy, or perhaps even hard way to disable features built into the °dONLNdbÔØ˚˛(Õsystem software°dONLNdr˚<¬(#ZTyour particular machine requires. It’s designed to work well, not to be toggle-able.°dONLNd«<Œ*Even the hard way isn’t a sure °dONLNdÊŒ˛)í=thing—trying to patch out all the Color QuickDraw traps could°dONLNd$<+k(GZ>confuse the rest of the system software, which internally may °dONLNdbk+˛(Gâuse undocumented routines to°dONLNd+<7û(SZaccomplish its tasks.°dONLNdïC<OÅ*>The easiest way to test on non-Color QuickDraw machines is to °dONLNd”CÅO˛(küget one. Fortunately, the°dONLNdÌO<[í(wZmachines without °dONLNd˛Oí[˛)VGColor QD are the lowest end of the Macintosh price spectrum—such as the°dONLNdF[<g¢(ÉZEMacintosh Classic, PowerBook 100, and Macintosh SE. You can probably °dONLNdã[¢g˛(É¿rent or borrow one°dONLNdûg<s((èZ5of these if the prices don’t fit your current budget.
  6472. °dONLNd‘ã<öÌ*'?Using a Macintosh PICT file that’s larger than available memory
  6473. °dONLNdö<¶b* Written:°dONLNdöඨ)L6/18/90 ◊X◊
  6474. (ÏZColor QuickDraw Q&As(Ïˇ1) of 31ˇ°¿Ù%%DSIDICT:_cv
  6475. currentdict /bu known {bu}if
  6476. userdict /_cv known not{userdict /_cv 30 dict put}if
  6477. _cv begin
  6478. /bdf{bind def}bind def
  6479. currentscreen/cs exch def/ca exch def/cf exch def
  6480. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6481. /ss{//cf //ca //cs setscreen}bdf
  6482. /stg{ss setgray}bdf
  6483. /strgb{ss setrgbcolor}bdf
  6484. /stcmyk{ss cvcmyk}bdf
  6485. /min1{dup 0 eq{pop 1}if}bdf
  6486. end
  6487. currentdict /bn known {bn}if
  6488. †øz◊#ˇ ˇˇˇˇ#◊ 
  6489. IR,Times
  6490. .+6-Macintosh Technical Notes /4/˘
  6491. °dONLNd)]*Last reviewed:°dONLNdd)à)L9/24/91°dONLNd5A=(]69How can I read a 2 MB PICT file into only 1 MB of memory?°dONLNdQAM** ___°dONLNdUYej*EYou can’t read it in since you don’t have enough memory, but drawing °dONLNdöYje⁄(Åàthe picture contained in°dONLNd≥eqê(ç6the file using a technique °dONLNdŒeêq⁄)xBcalled “spooling” increases your chances of using a 2 MB PICT file°dONLNdq}2(ô6with °dONLNdq2}Ω)F1 MB memory. Spooling is documented in the Color QuickDraw chapter of °dONLNd\qΩ}⁄(ô€Inside°dONLNdc}âI(•6    Macintosh°dONLNdl}Iâ«)1 Volume V (pages 88–89).
  6492. °dONLNdÖ°∞6(Ã6+Getting a single scan line from a PICT file
  6493. °dONLNd±∞º>* Written:°dONLNd∫∞dºà)L6/18/90°dONLNd¬º»](‰6Last reviewed:°dONLNd—ºd»à)L9/24/91°dONLNdŸ‘‡K(¸6CIs there any way to obtain a particular scan line from a PICT file?°dONLNd‡Ï** ___°dONLNd!¯À*VA PICT file may contain more than just pixmaps, so getting one scan line out of it is °dONLNdw¯À⁄( Ènot°dONLNd{·(,6*possible. The file may also contain other °dONLNd•·⁄)…2elements that overlap, such as rects and arcs. The°dONLNdÿ0(86only °dONLNd›0⁄)Yway to obtain a single line is to draw it off-screen and then, once the whole image is in°dONLNd7((D6/memory, you can go and study individual pixels.
  6494. °dONLNdg@O**''Determining pixel depth from PICT files
  6495. °dONLNdèO[>* Written:°dONLNdòOd[à)L6/20/90°dONLNd†[g](É6Last reviewed:°dONLNdØ[dgà)L9/17/91°dONLNd∑s<(õ6>How do you find out the pixel size of a PICT file on the disk?°dONLNdˆã** ___°dONLNd˙ó£z*GA picture is by nature independent of depth. For example, you can have °dONLNdAóz£⁄(øòa picture containing°dONLNdV£Øk(À6EDrawRects and LineTos and therefore lacking any info regarding depth.°dONLNdúª«x*KOn the other hand, if the picture you are looking at has pixmap opcodes in °dONLNdÁªx«⁄(„ñit, then each pixmap°dONLNd¸«”w(Ô6Icontains its own pixel size and in this case a picture can have a number °dONLNdE«w”⁄(Ôïof depths associated°dONLNdZ”fl:(˚6with it.°dONLNdcΘŸ*+If you want to see the pixel size for each °dONLNdéΟ˜⁄)¡6pixmap opcode in a picture, replace all the bottleneck°dONLNd≈˜¿(6\routines and every time the bitsProc is called you can see the pixmap and get the info out. °dONLNd!˜¿⁄(fiSince°dONLNd'ñ(+6the picture is in a file, you °dONLNdEñ⁄)~Acan use the spooling technique described in the QuickDraw chapter°dONLNdá$(76in °dONLNdä$u) Inside Macintosh°dONLNdöuø)Q Volume V. Be °dONLNd®ø⁄)J;ready to deal with multiple, possibly different, pixmaps as°dONLNd‰'s(C6Iwell as direct pixmaps if the picture was created under 32-bit QuickDraw.°dONLNd.3?è*”KnowsPICT,” on the °dONLNdB3è?¯)wDeveloper CD Series°dONLNdU3¯?»)i* disc, extracts this kind of information. °dONLNd3»?⁄)–The°dONLNdÉ?K=(g6?System 7.0 Picture Utilities package gets this information too.
  6496. °dONLNd√cr*' Direct RGB PICT file compression
  6497. °dONLNd‰r~>* Written:°dONLNdÌrd~é)L10/24/90°dONLNdˆ~ä](¶6Last reviewed:°dONLNd~däà)L2/14/91 ◊4◊˘
  6498. (Ï62) of 31(ÏîColor QuickDraw Q&Asˇñ◊#ˇ ˇˇˇˇ#◊ 
  6499. IR,Times
  6500. .+Z-Developer Support Center(-fi
  6501. December 1992 /X/
  6502. °dONLNd<)(EZVHow are bits packed in direct RGB PICT files created by 32-Bit QuickDraw? I looked at °dONLNdV)˛(Ethe°dONLNdZ)<5¿(QZGMacintosh Technical Note “Things You Wanted to Know About _PackBits…”, °dONLNd°)¿5˙(Qfi but this run°dONLNd≠)˙5˛):-°dONLNdÆ5<A*(]Z2length encoded compression is clearly inefficient °dONLNd‡5*A˛)Ó+for cases where pixelSize is greater than 8°dONLNd A<MT(iZbits. °dONLNdATM˛)XI write software for machines other than Macintosh that decodes PICT files; therefore, I°dONLNdkM<YC(uZ5cannot issue any QuickDraw calls such as _unpackBits.°dONLNd°Y<eN* ___°dONLNd•q<}z*
  6503. You’re quite °dONLNd≤qz}˛)>Pright; compressing direct pixels using straight run-length encoding doesn’t work°dONLNd}<âu(•ZAvery well. Fortunately, direct pixel maps aren’t compressed this °dONLNdD}uâ˛(•ìway. Compression schemes°dONLNd]â<ïì(±Zare discussed in °dONLNdnâìïÁ)WInside Macintosh°dONLNd~âÁïM)T Volume VI in the °dONLNdêâMï˛)f section titled “The New OpCodes:°dONLNd±ï<°ô(ΩZExpanded Format.”°dONLNd√≠<πÏ*WIn short, if the packType field holds the value 1, then no compression is done at all. °dONLNd≠Ïπ˛(’
  6504. The°dONLNdπ<≈’(·ZWcomplete pixel image is saved in the PICT. If the packType field holds the value 2 and °dONLNduπ’≈˛(·Û    the pixel°dONLNd≈<—¯(ÌZbmap is 32-bits per pixel, then all that’s done is that the alpha-channel byte is removed. So this:,
  6505. Courier
  6506.     °dONLNd‚›<Ë'*/                       00 FF FF FF  00 FF FF FF
  6507. °dONLNdÛ<ˇé*is compressed to:
  6508.     °dONLNd$ <    *)                       FF FF FF  FF FF FF
  6509. °dONLNdN!<-°*If the packType field °dONLNdd!°-˛)eIholds the value 3 and the pixel map is 16 bits per pixel, then run-length°dONLNdÆ-<9j(UZ    encoding °dONLNd∑-j9˛).Sis done, but not through PackBits. Instead, a run-length encoding algorithm private°dONLNd 9<E(aZ%to QuickDraw is used. This algorithm °dONLNd09E˛)«/is very similar to PackBits, but where PackBits°dONLNd`E<Qœ(mZcompresses runs of bytes, this °dONLNdEœQ˛)ì=routine compresses runs of words. The format of the resulting°dONLNdΩQ<]_(yZdata is °dONLNd≈Q_]˛)#Nexactly the same as described in the Technical Note “Things You Wanted to Know°dONLNd]<ii(ÖZ=About _PackBits…”, but you’ll get words instead. To build on °dONLNdQ]ii˛(Öáthe example in this Tech Note,°dONLNdpi<u[(ëZ?lets say the 16-bit pixel image begins with these pixel values:
  6510.     °dONLNd∞Å<åw*?    AAAA AAAA AAAA 8080 0000 2A2A AAAA AAAA AAAA AAAA 8080 0000°dONLNdã<ñw*
  6511. ?    2A2A 2222 AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA°dONLNd0ü<™Ω*MAfter being packed by QuickDraw’s internal compression routine, this becomes:°dONLNd~≥<æs*     FE AAAA°dONLNdäΩ<»•*
  6512.     02 8080 0000 2A2A°dONLNd†«<“s*
  6513.     FD AAAA°dONLNd¨—<‹æ*
  6514.     03 8080 0000 2A2A 2222°dONLNd«€<Ês*
  6515.     F7 AAAA
  6516. °dONLNd”Ò<˝F*or
  6517.     °dONLNd÷    <Ü*B    FEAA AA02 8080 0000 2A2A FDAA AA03 8080 0000 2A2A 2222 F7AA AA°dONLNd<h*
  6518. <    *      *                 *      *                      *
  6519. °dONLNdV)<5**where the asterisks mark the flag-counter °dONLNdÄ)5˛)À2bytes. Notice that you can’t assume that the pixel°dONLNd≥5<AQ(]Z:values are word-aligned. PackBits packs data 127 bytes at °dONLNdÌ5QA˛(]o%a time, though it will do this for up°dONLNd    A<MT(iZ;to 32,767 total bytes. Similarly, the internal compression °dONLNd    NATM˛(ir!routine packs data 127 words at a°dONLNd    pM<YT(uZtime.°dONLNd    ve<q°*If the packType field °dONLNd    åe°q˛)eIholds the value 4 and the pixel map is 32-bits per pixel, then run-length°dONLNd    ÷q<}÷(ôZencoding via PackBits is done, °dONLNd    ıq÷}˛)ö:but only after some preprocessing is done. QuickDraw first°dONLNd
  6520. 0}<âª(•ZNrearranges the color components of the pixels so that each color component of °dONLNd
  6521. ~}ªâ˛(•Ÿevery pixel is°dONLNd
  6522. çâ<ïz(±Z
  6523. consecutive. °dONLNd
  6524. öâzï˛)>PSo the following four pixels (the row below the pixel values indicates a = alpha°dONLNd
  6525. Îï<°Q(ΩZ=channel, r = red, g = green, b = blue, and the pixel offset): ◊X◊
  6526. */Color QuickDraw Q&As(Ïˇ3) of 31ˇ
  6527. ◊#ˇ ˇˇˇˇ#◊ 
  6528. IR,Times
  6529. .+6-Macintosh Technical Notes /4/˘,
  6530. Courier
  6531.     °dONLNd(N*>            00 FF FF FF  00 FF C0 00  00 FF 80 00  00 C0 80 00°dONLNd?'2N*
  6532. >            a0 r0 g0 b0  a1 r1 g1 b1  a2 r2 g2 b2  a3 r3 g3 b3
  6533. °dONLNd~=Iã*is rearranged to become:
  6534.     °dONLNdóU`
  6535. *1            FF FF FF C0  FF C0 80 80  FF 00 00 00°dONLNd…_j
  6536. *
  6537. 1            r0 r1 r2 r3  g0 g1 g2 g3  b0 b1 b2 b3
  6538. °dONLNd˚uÅá*The first four bytes are °dONLNduáÅ⁄)oGthe red components of the four pixels, the next four bytes indicate the°dONLNd\Åçb(©6Bgreen components of the four pixels, and so on. The alpha channel °dONLNdûÅbç⁄(©Äisn’t included unless the°dONLNd∏çô(µ64cmpCount field contains 4 rather than the normal 3. °dONLNdÏçô⁄)ˆ*If cmpCount contains 4, then all the alpha°dONLNdô•≥(¡6 channel bytes are placed before °dONLNd7ô≥•⁄)õ<the red bytes. Once this is done, then PackBits is called to°dONLNdt•±•(Õ6compress the rearranged data.°dONLNdíΩ…Ç*GThose are the only four compression schemes (including no compression) °dONLNdŸΩÇ…⁄(†that are supported°dONLNdÏ…’à(Ò6for direct pixel maps in °dONLNd…à’⁄)pBPICTs. As always, reading PICTs yourself puts you in danger of not°dONLNdH’·D(˝69being able to read PICTs generated by future versions of °dONLNdÅ’D·⁄(˝bQuickDraw. For compatibility°dONLNdû·Ì`(    6reasons, these °dONLNd≠·`Ì⁄)HJcompression algorithms as I’ve described them probably can’t change in the°dONLNd¯Ì˘ï(6Ofuture. It’s possible that new values for packType could be implemented though.°dONLNdH9*X-Ref:°dONLNdOã* EMacintosh Technical Note “Things You Wanted to Know About _PackBits…”
  6539. °dONLNdï5DÁ*'Saving 32-bit Macintosh PICTs
  6540. °dONLNd≥DP>* Written:°dONLNdºDdPé)L10/30/90°dONLNd≈P\](x6Last reviewed:°dONLNd‘Pd\à)L2/20/91°dONLNd‹ht¿(ê6!I am using a packType=4 and have °dONLNd˝h¿t⁄)®9several questions about saving Macintosh 32-bit images in°dONLNd7tÄ_(ú6a PICT format:°dONLNdFåòï*K1. What are the ramifications of using cmpCount=3 as opposed to cmpCount=4?°dONLNdí§∞™*2. How is the pixData actually °dONLNd±§™∞⁄)í@stored? According to several references, each line is run-length°dONLNdÚ∞º/(ÿ6:encoded; that is, [byteCount][data]. If rowBytes>250 then °dONLNd,∞/º⁄(ÿM"byteCount is a word. After looking°dONLNdOº»®(‰6at several examples, I came to °dONLNdnº®»⁄)ê@the conclusion that you are actually using PackBits and that the°dONLNdØ»‘fi(6(term “run-length” encoded is a misnomer.°dONLNdÿ‘‡** ___°dONLNd‹Ï¯Ù*+1. The difference between using cmpCount=3 °dONLNdÏÙ¯⁄)‹0or cmpCount=4 is that in the first case only the°dONLNd8¯õ( 6RR, G, and B values are stored in the picture; in the second case QuickDraw stores °dONLNdä¯õ⁄( πin the picture°dONLNdô°(,6Pthe alpha channel plus R, G, and B. cmpCount=4 can be used when it is important °dONLNdȰ⁄(,ø to also save°dONLNdˆ=(86=the alpha channel (as when you have some flags stored there).°dONLNd4(4X*B2. Unless rowBytes is less than 8, the pixmap is compressed using °dONLNdv(X4⁄(PvPackBits, and the length is°dONLNdí4@p(\6@a word or a byte depending on rowBytes, but it always refers to °dONLNd“4p@⁄(\éthe number of bytes°dONLNdÊ@Lã(h6Ocomprising one scan line. My guess is that “run-length encoding” refers to the °dONLNd    5@ãL⁄(h©fact that pictures°dONLNd    HLXÕ(t6&have data organized one row at a time.°dONLNd    odpò*OTo show how direct RGB pixmaps are stored inside a picture, I am including the °dONLNd    ædòp⁄(å∂
  6541. decoding of a°dONLNd    Ãp|O(ò6
  6542. picture that °dONLNd    ŸpO|⁄)7OI created to show how the different packing schemes change the resulting pixmap°dONLNd
  6543. )|àÜ(§6Oopcode data. First I created a direct RGB pixmap and drew three lines into it. °dONLNd
  6544. x|Üà⁄(§§The first line is 8°dONLNd
  6545. åàîö(∞6Ppixels long with a color of {0x1111,0xAAAA, 0x7777}, the third line is 8 pixels °dONLNd
  6546. ‹àöî⁄(∞∏ of {0xFFFF,°dONLNd
  6547. Ëî†C(º60x3333, °dONLNd
  6548. îC†⁄)+S0xBBBB} and the line in between is two pixels of the first color then two pixels of°dONLNd D†¨0(»6;the second color and so on until you make 8 pixels. Then I °dONLNd †0¨⁄(»N"created a picture made of CopyBits ◊4◊˘
  6549. (Ï64) of 31(ÏîColor QuickDraw Q&Asˇ≤◊#ˇ ˇˇˇˇ#◊ 
  6550. IR,Times
  6551. .+Z-Developer Support Center(-fi
  6552. December 1992 /X/
  6553. °dONLNd<)∏(EZJcalls copying the same lines but using different packing schemes. Finally °dONLNdJ∏)˛(E÷ I dumped the°dONLNdW)<5â(QZDcontents and the result is what you see here. I have put comments I °dONLNdõ)â5˛(Qßthink help make it clear°dONLNd¥5<A>(]Z5how the packing scheme of choice changes the results.°dONLNdÍM<YD*I °dONLNdÏMDY€)recommend that you have the °dONLNdM€Y.)óInside Macintosh°dONLNdM.Y˛)S& Volume V QuickDraw chapter at hand to°dONLNd?Y<e\(ÅZ<check the opcodes and data associated with them. If you had °dONLNd{Y\e|(ÅzInside °dONLNdÇY|e≠)     Macintosh°dONLNdãY≠e˛)1 Volume VI then°dONLNdõe<q‰(çZ you wouldn’t need to also check °dONLNdªe‰q˛)®3the 32-Bit QuickDraw docs for the direct RGB pixmap°dONLNdÔq<}~(ôZ=opcodes. The Technical Note “Things You Wanted To Know about °dONLNd,q~}˛(ôú_PackBits…” gives details°dONLNdF}<âÊ(•Z#on how the packed data is arranged.,
  6554. Courier
  6555.     °dONLNdjï<†ï*E0256 0000 0000 0008 0008                   /* size and rect        */°dONLNd∞©<¥ï*E0011 02FF 0C00 FFFF FFFF                   /* PICT2 Header         */°dONLNdˆ≥<æ¥*
  6556. 0000 0000 0000 0000 0008°dONLNdΩ<»¥*
  6557. 0000 0008 0000 0000 0000°dONLNd(—<‹ï*E001E                                       /* Default hilite       */°dONLNdnÂ<ï*E001A FFFF 3333 BBBB                        /* RGB Fore Color       */°dONLNd¥˘<ï*E0001 000A 8001 8001 7FFF 7FFF              /* ClipRgn              */°dONLNd˙
  6558. <¬*N009A              /* direct pixels opcode; see IM VI QD chapter for details */°dONLNdI<"¬*
  6559. N0000 00FF 8020 0000 0000 0003 0008 0000    /* See IM V or VI QuickDraw chapter°dONLNdò!<,F*
  6560. */°dONLNdõ+<6≥*
  6561. K0001 0000 0000 0048 0000 0048 0000 0010    /* packType 0001 = no packing */°dONLNdÁ5<@ˇ*
  6562. '0020 0003 0008 0000 0000 006D A7DC 0000°dONLNd?<Jˇ*
  6563. '0000 0000 0000 0003 0008 0000 0000 0003°dONLNd7I<Ti*
  6564.     0008 0000°dONLNdA]<h©*I0011 AA77 0011 AA77 0011 AA77 0011 AA77    /* line one xRGB after xRGB */°dONLNdãg<rˇ*
  6565. '0011 AA77 0011 AA77 0011 AA77 0011 AA77°dONLNd≥{<ÜÅ*A0011 AA77 0011 AA77 00FF 33BB 00FF 33BB    /* second line same */°dONLNdıÖ<êˇ*
  6566. '0011 AA77 0011 AA77 00FF 33BB 00FF 33BB°dONLNdô<§Å*A00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB    /* third line same  */°dONLNd_£<Æˇ*
  6567. '00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB°dONLNdá∑<¬∏*L009A                                       /* same direct pixels opcode   */°dONLNd‘¡<Ãˇ*
  6568. '0000 00FF 8020 0000 0000 0003 0008 0000°dONLNd¸À<÷∏*
  6569. L0002 0000 0000 0048 0000 0048 0000 0010    /* packType 2 = fourth byte off*/°dONLNdI’<‡ˇ*
  6570. '0020 0003 0008 0000 0000 006D A7DC 0000°dONLNdqfl<͡*
  6571. '0000 0000 0000 0003 0008 0003 0000 0006°dONLNdôÈ<Ùi*
  6572.     0008 0000°dONLNd£˝<∏*L11AA 7711 AA77 11AA 7711 AA77              /* one line of RGB after RGB   */°dONLNd<∏*
  6573. L11AA 7711 AA77 11AA 7711 AA77              /* compare with previous       */°dONLNd=<&Y*911AA 7711 AA77 FF33 BBFF 33BB              /* same here*/°dONLNdw%<0Õ*
  6574. 11AA 7711 AA77 FF33 BBFF 33BB°dONLNdï9<DY*9FF33 BBFF 33BB FF33 BBFF 33BB              /* and here */°dONLNdœC<NÕ*
  6575. FF33 BBFF 33BB FF33 BBFF 33BB°dONLNdÌW<bh*<009A                                       /* bits opcode */°dONLNd    *a<lˇ*
  6576. '0000 00FF 8020 0000 0000 0003 0008 0000°dONLNd    Rk<vö*
  6577. F0004 0000 0000 0048 0000 0048 0000 0010    /* packType 4 = pack     */°dONLNd    ôu<Äö*
  6578. F0020 0003 0008 0000 0000 006D A7DC 0000    /* componentCount = 3    */°dONLNd    ‡<äö*
  6579. F0000 0000 0000 0003 0008 0006 0000 0009    /* R,G and B separated   */°dONLNd
  6580. 'â<îi*
  6581.     0008 0000°dONLNd
  6582. 1ù<®÷*R                    /* for details on packed data see Tech Note referenced above*/ ◊X◊
  6583. *(Color QuickDraw Q&As(Ïˇ5) of 31ˇÓ◊#ˇ ˇˇˇˇ#◊ 
  6584. IR,Times
  6585. .+6-Macintosh Technical Notes /4/˘,
  6586. Courier
  6587.     °dONLNd({*G06                  /* first line made of 6 bytes including count    */°dONLNdH'20*
  6588. 8F9 11F9 AAF9 77     /* -(-7)+1 of 11, -(-7)+1 of AA, and°dONLNdÅ1<{*
  6589. G                                   -(-7)+1 of 77 -> 8 RGB triplets   */°dONLNd…;F{*
  6590. G19                                   /* second row made of $19 bytes */°dONLNdEPN*
  6591. >1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB°dONLNdPOZv*
  6592. F                                           /* $17+1 unpacked values */°dONLNdóYdû*
  6593. N06                                         /* third line same as first      */°dONLNdÊcnû*
  6594. NF9FF F933 F9BB                             /* repeated R and B and G values */°dONLNd5wÇq*E009A                                          /* bits opcode again */°dONLNd{Åå€*
  6595. '0000 00FF 8020 0000 0000 0003 0008 0000°dONLNd£ãñû*
  6596. N0004 0000 0000 0048 0000 0048 0000 0010       /* same packing = 4 but       */°dONLNdÚï†û*
  6597. N0020 0004 0008 0000 0000 006D A7DC 0000       /* component count = 4        */°dONLNdAü™û*
  6598. N0000 0000 0000 0003 0008 0009 0000 000C       /* alpha channel, R, G, and B */°dONLNdê©¥E*
  6599.     0008 0000°dONLNdöΩ»N*>08                                            /* first line */°dONLNdŸ«“|*
  6600. F9 00F9 11F9 AAF9 77°dONLNdÓ—‹û*
  6601. N                /* same as before but packing the high byte (00 value) also */°dONLNd=€Êû*
  6602. N1B    /* second line first has -(-7)+1 '00' and then the same line as above */°dONLNdåÂg*
  6603. CF900 1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB°dONLNd–Ô˙î*
  6604. L08                                            /* third line same as first */°dONLNd˘w*
  6605. F900 F9FF F933 F9BB°dONLNd1S*
  6606. ?00FF                                          /* end of PICT */
  6607. °dONLNdq%*9A section of the code that produces this picture follows:
  6608.     °dONLNd´1<*4    RGBColor    oneColor = {0x1111, 0xaaaa, 0x7777},°dONLNd‡;F*
  6609. 2                twoColor = {0xffff,0x3333,0xbbbb};°dONLNdOZô*M    SetGWorld(GgwPtr, nil);                   /* set the off-screen GWorld */°dONLNdacnÔ*+    if ( LockPixels(GgwPtr -> portPixMap) )°dONLNdçmx1*
  6610.     {°dONLNdìÅå€*'        EraseRect(&(GgwPtr->portRect));°dONLNdªï†∏*         RGBForeColor(&oneColor);°dONLNd‹ü™|*
  6611.         MoveTo(0,0);°dONLNdÒ©¥|*
  6612.         LineTo(7,0);°dONLNd≥æ|*
  6613.         MoveTo(0,1);°dONLNdΩ»|*
  6614.         LineTo(1,1);°dONLNd0«“∏*
  6615.          RGBForeColor(&twoColor);°dONLNdQ—‹|*
  6616.         MoveTo(2,1);°dONLNdf€Ê|*
  6617.         LineTo(3,1);°dONLNd{Â∏*
  6618.          RGBForeColor(&oneColor);°dONLNdúÔ˙|*
  6619.         MoveTo(4,1);°dONLNd±˘|*
  6620.         LineTo(5,1);°dONLNdΔ∏*
  6621.          RGBForeColor(&twoColor);°dONLNdÁ
  6622. |*
  6623.         MoveTo(6,1);°dONLNd¸"|*
  6624.         LineTo(7,1);°dONLNd!,|*
  6625.         MoveTo(0,2);°dONLNd&+6|*
  6626.         LineTo(7,2);°dONLNd;5@Ω*
  6627. !        SetRect(&localR,0,0,8,3);°dONLNd]?J|*
  6628.         rr = localR;°dONLNdrIT˘*
  6629. -        p = OpenPicture(&(GgwPtr->portRect));°dONLNd†S^Æ*
  6630.         /* first no packing */°dONLNdø]h*
  6631. 2        (*(GgwPtr -> portPixMap)) -> packType = 1;°dONLNdÚgrÖ*
  6632. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNd    <q|Â*
  6633. )                &rr,&localR,srcCopy,nil);°dONLNd    f{Ü*
  6634. 0        /* second pack 2: remove alpha chanel */°dONLNd    óÖêÃ*
  6635. $            OffsetRect(&localR,0,3);°dONLNd    ºèö*
  6636. 2        (*(GgwPtr -> portPixMap)) -> packType = 2;°dONLNd    Ôô§Ö*
  6637. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNd
  6638. 9£ÆÂ*
  6639. )                &rr,&localR,srcCopy,nil); ◊4◊˘
  6640. *"6) of 31(ÏîColor QuickDraw Q&Asˇ ◊#ˇ ˇˇˇˇ#◊ 
  6641. IR,Times
  6642. .+Z-Developer Support Center(-fi
  6643. December 1992 /X/,
  6644. Courier
  6645.     °dONLNd<(^(DZ:        /* third pack 4: packing component by component */°dONLNd;'<2*
  6646. $            OffsetRect(&localR,0,3);°dONLNd`1<<6*
  6647. 2        (*(GgwPtr -> portPixMap)) -> packType = 4;°dONLNdì;<F©*
  6648. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNd›E<P    *
  6649. )                &rr,&localR,srcCopy,nil);°dONLNdO<Z§*
  6650. H        /* The last case is pack 4 but storing the alpha channel also */°dONLNdPY<d*
  6651. $            OffsetRect(&localR,0,3);°dONLNduc<n6*
  6652. 2        (*(GgwPtr -> portPixMap)) -> packType = 4;°dONLNd®m<x6*
  6653. 2        (*(GgwPtr -> portPixMap)) -> cmpCount = 4;°dONLNd€w<Ç©*
  6654. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNd%Å<å    *
  6655. )                &rr,&localR,srcCopy,nil);°dONLNdOã<ñØ*
  6656.         ClosePicture();°dONLNdgï<†ˇ*
  6657. '    UnlockPixels(GgwPtr -> portPixMap);°dONLNdèü<™U*
  6658.     }
  6659. °dONLNdïµ<¡]*X-Ref:°dONLNdú¡<Õû* “Color QuickDraw,”°dONLNdÆ¡ûÕ˘)b Inside Macintosh, °dONLNd¡¡˘Õ))[Volume V°dONLNd Õ<Ÿ°(ıZ“Color QuickDraw,” °dONLNd›Õ°Ÿˆ)eInside Macintosh,°dONLNdÓÕˆŸ-)U
  6660.  Volume VI°dONLNd˘Ÿ<Â∞(ZEMacintosh Technical Note “Things You Wanted To Know about _PackBits…”
  6661. °dONLNd?˝< Δ*'4BitMapToRgn for non-Color QuickDraw Macintosh models
  6662. °dONLNdt <b* Written:°dONLNd} à¨)L11/9/90°dONLNdÖ<$Å(@ZLast reviewed:°dONLNdîà$¨)L2/20/91°dONLNdú0<<†(XZEIs _BitmapToRegion available on any pre-System 7 non-Color QuickDraw °dONLNd·0†<˛(Xæconfigurations such°dONLNdı<<Hˆ(dZ'as the Macintosh Classic, Plus, or SE? °dONLNd<ˆH˛)∫9If not, is source or a library module available so that I°dONLNdVH<T(pZEdon’t have to take the time and compatibility risk of rolling my own?°dONLNdúT<`N* ___°dONLNd†l<xƒ*BitMapToRegion works on °dONLNd∏lƒx˛)à;pre-color Macintosh systems. You can license BitMapToRegion°dONLNdÙx<ÑS(†Zfrom°dONLNd˘ê<ú§*    Software Licensing°dONLNdú<®∞*     Apple Computer, Inc.°dONLNd)®<¥“*     20525 Mariani Ave. MS:38-I°dONLNdH¥<¿Ø*     Cupertino, CA 95014°dONLNd`¿<ë*     AppleLink: SW.LICENSE°dONLNdzÃ<ÿ¥*     Phone:(408) 974-4667 ◊X◊
  6663. *¯Color QuickDraw Q&As(Ïˇ7) of 31ˇ:◊#ˇ ˇˇˇˇ#◊ 
  6664. IR,Times
  6665. .+6-Macintosh Technical Notes /4/˘
  6666. °dONLNd)8s*'0Macintosh QuickDraw pixel map stack requirements
  6667. °dONLNd18D>* Written:°dONLNd:8dDà)L12/3/90°dONLNdBDP](l6Last reviewed:°dONLNdQDdPà)L5/21/91°dONLNdY\h§(Ñ6What are the guidelines for °dONLNdu\§h⁄)å7determining how much of an image CopyBits can copy to a°dONLNd≠ht±(ê6ZMacintosh pixel map at one time, given a particular set of characteristics for the source °dONLNdh±t⁄(êœmap and°dONLNdtÄ[(ú6Athe destination map and given how much stack space is available? °dONLNdPt[Ä⁄(úyFor example, say that we°dONLNdiÄå+(®68have an 8-bit-deep pixmap to be copied to a 32-bit-deep °dONLNd°Ä+å⁄(®I pixMap using the ditherCopy mode°dONLNd¬åòG(¥6>and expanded by a factor of 4, and we have 45K of stack space.°dONLNdò§** ___°dONLNd∞º–*XCopyBits’ stack requirement depends on the width of each scan line (rowBytes). The rule °dONLNd]∞–º⁄(ÿÓof°dONLNd`º»”(‰6(thumb is that you need at least as much °dONLNdດ»⁄)ª4stack as the rowBytes value in your image (which can°dONLNdΩ»‘N(6>be huge with 32-Bit QuickDraw), with the following additional °dONLNd˚»N‘⁄(lmodifiers: Add an additional°dONLNd‘‡¬(¸6[rowBytes for dithering; add an additional rowBytes for any stretching (source rect != dest °dONLNds‘¬‡⁄(¸‡rect);°dONLNdz‡ÏÉ(6Iadd an additional rowBytes for any color map changing; add an additional °dONLNd√‡ÉÏ⁄(°rowBytes for any°dONLNd‘ϯ‰(6,color aliasing. The stack space you need is °dONLNdω¯⁄)Ã1roughly five times the rowBytes of your image. In°dONLNd2¯c( 6Dgeneral, you’re better off processing narrower scan lines. Reducing °dONLNdv¯c⁄( Åthe vertical size will not°dONLNdë (,62affect stack requirements. Narrow, tall bands (if °dONLNd√ ⁄)Ù'you can use them) will reduce the stack°dONLNdÎY(86
  6668. requirements.
  6669. °dONLNd˘4Cù*'7Color and non-Color QuickDraw trap dispatch differences
  6670. °dONLNd1CO>* Written:°dONLNd:CdOà)L1/28/91°dONLNdBO[](w6Last reviewed:°dONLNdQOd[à)L2/13/91°dONLNdYgs¿(è6RWhy does a call to RGBForeColor cause a corruption of the stack without resulting °dONLNd´g¿s⁄(èfiin an°dONLNd±sm(õ6Bunimplemented trap error on non-Color QuickDraw Macintosh systems?°dONLNdÙã** ___°dONLNd¯ó£¢*The trap dispatcher on Color °dONLNdó¢£⁄)ä<QuickDraw and non-Color QuickDraw machines are different. If°dONLNdR£ØÖ(À6you look at page 89 of °dONLNdi£ÖØ÷)mInside Macintosh°dONLNdy£÷Ø)Q Volume °dONLNdÅ£Ø⁄)+-I, you’ll see the toolbox trap word format as°dONLNdØØªï(◊6Jit was in the days before Color QuickDraw. Bit 9 was “reserved for future °dONLNd˘Øïª⁄(◊≥ use” and was°dONLNdª«t(„6ignored by the trap °dONLNdªt«⁄)\Jdispatcher, and so it was normally set to 0. That means that valid toolbox°dONLNde«”ù(Ô6traps could either look like °dONLNdÇ«ù”⁄)Ö:$A8XX or $A9XX as long as the auto-pop bit was turned off.°dONLNdΩ”fl(˚65Color QuickDraw machines have a trap dispatcher that °dONLNdÚ”fl⁄(˚9(uses that reserved bit to allow for more°dONLNdflÎ(64trap words, and therefore it has a much larger trap °dONLNdOflÎ⁄)Ô*dispatch table. Color QuickDraw traps have°dONLNdzΘN(6?that reserved bit set, so those traps look like $AAXX or $ABXX.°dONLNd∫…*TWhen a non-Color QuickDraw machine tests to see if a trap is implemented or not, it °dONLNd    …⁄(+Ájust°dONLNd    |(76Pchecks the trap dispatch table to see if a routine is implemented for that trap °dONLNd    c|⁄(7öor not. Because the°dONLNd    w'](C6reserved bit is °dONLNd    á]'⁄)EKignored, trap words that look like $AAXX are treated as equivalent to $A8XX°dONLNd    ”'3b(O6and trap words °dONLNd    ‚'b3⁄)JJthat look like $ABXX are treated as equivalent to $A9XX. The trap word for°dONLNd
  6671. -3?®([6RGBForeColor is $AA14. If °dONLNd
  6672. G3®?⁄)ê7you call RGBForeColor on a non-Color QuickDraw machine,°dONLNd
  6673. ?K(g6-$AA14 is treated as $A814, which is the trap °dONLNd
  6674. ¨?K⁄)È*word for SetFractEnable. SetFractEnable is°dONLNd
  6675. ◊KWæ(s6Simplemented on 128K ROM machines or greater, so no unimplemented trap error occurs.°dONLNd +co_*If you look at °dONLNd :c_o⁄)GKrecent DTS sample programs, such as the Utilities sample (SC.025.Utilities,°dONLNd Üo{ä(ó6which you can find on °dONLNd úoä{⁄)r@AppleLink in Developer Support and on the current developer CD),°dONLNd ›{á◊(£6+you’ll see a routine in Utilities.c called °dONLNd {◊á⁄)ø6TrapExists. It takes into account the size of the trap°dONLNd ?áìI(Ø6Edispatch table so that you can tell in one call whether a routine is °dONLNd ÑáIì⁄(Øgimplemented or not regardless°dONLNd ¢ìüÜ(ª6Mof whether it’s a Color QuickDraw trap or not and regardless of what kind of °dONLNd ÔìÜü⁄(ª§Macintosh you’re°dONLNd
  6676. ü´P(«6 running on. ◊4◊˘
  6677. *%8) of 31(ÏîColor QuickDraw Q&AsˇT◊#ˇ ˇˇˇˇ#◊ 
  6678. IR,Times
  6679. .+Z-Developer Support Center(-fi
  6680. December 1992 /X/
  6681. °dONLNd)<5Å(QZ
  6682. Under system °dONLNd
  6683. )Å5˛)ELsoftware version 7.0, the trap dispatcher is modified on non-Color QuickDraw°dONLNdZ5<A™(]Zmachines so that many °dONLNdp5™A˛)nBColor QuickDraw traps are implemented and work as well as they can°dONLNd≥A<Mñ(iZin black and white.
  6684. °dONLNd«e<tz*'-Macintosh OpenCPicture 72-dpi calculation bug
  6685. °dONLNdıt<Äb* Written:°dONLNd˛tàĨ)L2/12/91°dONLNdÄ<åÅ(®ZLast reviewed:°dONLNdÄàå¨)L2/20/91°dONLNdò<§´(¿ZThe 32-Bit QuickDraw °dONLNd2ò´§˛)oG_OpenCPicture call incorrectly calculates the 72-dpi frame width if the°dONLNdz§<∞ã(ÃZBheight of the native resolution srcRect exceeds 910 dots. To work °dONLNdº§ã∞˛(éaround this problem, I°dONLNd”∞<ºq(ÿZ:calculate the 72-dpi frame independently, and store it in °dONLNd
  6686. ∞qº˛(ÿèthe PicHandle returned by°dONLNd'º<»à(‰Z_OpenCPicture.°dONLNd6»<‘N* ___°dONLNd:‡<ϧ*It’s a known bug that °dONLNdP‡§Ï˛)hDunder Macintosh system software versions 6.0.5 and 6.0.7 with 32-Bit°dONLNdïÏ<¯fl(ZSQuickDraw 1.2, OpenCPicture doesn’t properly calculate the right coordinate of the °dONLNdËÏfl¯˛(˝72-dpi°dONLNdÔ¯<l( Z    picFrame °dONLNd¯¯l˛)0Sif the height of the srcRect (native resolution rectangle) multiplied by 72 exceeds°dONLNdL<.(,Z.$0000FFFF. That works out to a maximum height °dONLNdz.˛)Ú*of 910 pixels, just as you found. This bug°dONLNd•<J(8Zis °dONLNd®J˛)Pfixed in System 7.0, but gestaltQuickdrawVersion returns $0220 both under system°dONLNd˘<(€(DZ!software versions 6.0.5 and 7.0, °dONLNd€(˛)ü=so you can’t tell whether the bug is fixed that way. Instead,°dONLNdX(<4t(PZ you should °dONLNdc(t4˛)8Ruse Gestalt with the gestaltSystemVersion selector. If the returned value is $0700°dONLNd∂4<@t(\ZCor greater, then let OpenCPicture handle the picFrame calculation; °dONLNd˘4t@˛(\íotherwise you should do the°dONLNd@<Lú(hZcalculation yourself.
  6687. °dONLNd+d<sH*'"GetGWorldPixMap bug and workaround
  6688. °dONLNdNs<b* Written:°dONLNdWsà¨)L3/12/91°dONLNd_<ãÅ(ßZLast reviewed:°dONLNdnàã¨)L10/9/91°dONLNdvó<£(øZ&Why does GetGWorldPixMap (when called °dONLNdúó£˛)◊.on a Macintosh II, IIcx, or IIx running system°dONLNdÀ£<؇(ÀZWsoftware version 6.0.5 or 6.0.7 with 32-Bit QuickDraw 1.2) return a combination of the °dONLNd"£‡Ø˛(À˛device°dONLNd)Ø<ªÆ(◊ZQfield (two bytes) and the first two bytes of the portPixMap field? Is this a bug?°dONLNd{ª<«N* ___°dONLNd”<flì*Your analysis of °dONLNdê”ìfl˛)WEGetGWorldPixMap is exactly right: It doesn’t work correctly in system°dONLNd÷fl<Îs(Z=software versions 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2. °dONLNdflsβ(ëIt returns a value that’s two°dONLNd1Î<˜(Z/bytes before the value it’s supposed to return.°dONLNda<Ö*The solution is °dONLNdqÖ˛)IHto use GWorldPtr->portPixMap instead of GetGWorldPixMap. It’s safe to do°dONLNd∫</(7Z/this, but you should use GetGWorldPixMap under °dONLNdÈ/˛)Û*System 7. Not only is the bug fixed there,°dONLNd<'D(CZ7but dereferencing the port is dangerous under System 7 °dONLNdKD'˛(Cb$because it may not be CGrafPort. Use°dONLNdp'<3T(OZ5Gestalt with the gestaltQuickdrawVersion selector to °dONLNd•'T3˛(Ordetermine whether you can use°dONLNd√3<?([Z&GetGWorldPixMap. If Gestalt returns a °dONLNdÈ3?˛)›(value from gestalt8BitQD ($0100) through°dONLNd    ?<KC(gZ/gestalt32BitQD12 ($0220), then GetGWorldPixMap °dONLNd    A?CK˛(ga$either doesn’t exist or is the buggy°dONLNd    fK<Wz(sZversion. If it °dONLNd    uKzW˛)>Kreturns gestalt32BitQD13 ($0230) or higher, then GetGWorldPixMap does exist°dONLNd    ¡W<cM(Z4and works correctly. Interestingly, GetGWorldPixMap °dONLNd    ıWMc˛(k"can be called on a black-and-white°dONLNd
  6689. c<o\(ãZ;QuickDraw machine under System 7. It returns a handle to a °dONLNd
  6690. Sc\o˛(ãz#structure that should be treated as°dONLNd
  6691. wo<{ª(óZa bitmap structure, though °dONLNd
  6692. íoª{˛)Bthere are some undocumented fields after the normal bitmap fields.°dONLNd
  6693. ’{<áÉ(£ZBTo tell whether GetGWorldPixMap is available on a black-and-white °dONLNd {Éá˛(£°QuickDraw machine, you°dONLNd .á<ìx(ØZ must check °dONLNd 9áxì˛)<Lthe system software version by calling Gestalt with the gestaltSystemVersion°dONLNd Üì<üä(ªZFselector. If it returns $0700 or higher, GetGWorldPixMap is available. ◊X◊
  6694. *1Color QuickDraw Q&As(Ïˇ9) of 31ˇ∫◊#ˇ ˇˇˇˇ#◊ 
  6695. IR,Times
  6696. .+6-Macintosh Technical Notes /4/˘
  6697. °dONLNd)8G*'(System 7 TextMode problem and workaround
  6698. °dONLNd)8D>* Written:°dONLNd28dDà)L6/12/91°dONLNd:DP](l6Last reviewed:°dONLNdIDdPà)L8/13/91°dONLNdQ\h_(Ñ6BOur application uses the TextMode (blend + mask) as documented in °dONLNdì\_h±(Ñ}Inside Macintosh°dONLNd£\±h⁄)R Volume°dONLNd´ht©(ê6VV (blend is equal to the current ditherCopy constant) to make translucent text. Under °dONLNdh©t⁄(ê«    System 7,°dONLNd tÄf(ú6Dthis transfer mode causes garbage to appear when the text is drawn. °dONLNdOtfÄ⁄(úÑIs there a way to work°dONLNdfÄå’(®6(around the problem? Will there be a fix?°dONLNdèåò** ___°dONLNdì§∞-*The °dONLNdó§-∞⁄)Uproblem you are seeing is due to the use of CopyDeepMask instead of the old-fashioned°dONLNdÌ∞º(ÿ65CopyBits to do the job. It is being studied now, and °dONLNd"∞º⁄)˘+the hope is that it will work as advertised°dONLNdNº»–(‰6'in a future release. One workaround is °dONLNduº–»⁄)∏8to render the text to an off-screen pixmap and then call°dONLNdÆ»‘4(6=CopyBits (using blendMode) to actually put it in the picture.
  6699. °dONLNdÏÏ˚©*'9Using dithering and animation on the same Macintosh image
  6700. °dONLNd&˚>* Written:°dONLNd/˚dà)L6/19/91°dONLNd7](/6Last reviewed:°dONLNdFdé)L10/15/91°dONLNdO+0(G6:When setting up a dithered grayscale image for subsequent °dONLNdâ0+⁄(GN$animation (to adjust brightness, for°dONLNdÆ+7J(S6
  6701. example), °dONLNd∏+J7⁄)2Ra conflict arises between the use of Palette animation and the ditherCopy CopyBits°dONLNd 7C~(_6mode. This problem °dONLNd7~C)fis demonstrated in the °dONLNd57C)rdevelop°dONLNd<7C⁄)%% #5 GiMeDaPalette code sample: If you°dONLNdbCO∑(k6 change srcCopy to ditherCopy in °dONLNdÇC∑O⁄)ü;the CopyBits call, then run the program and select Animate,°dONLNdæO[(w6the resulting image is °dONLNd’O[⁄)gGpure black and white, with what appears to be an attempt to dither with°dONLNd[gè(É6Sjust the black-and-white color table entries (that are not reserved for animation).°dONLNdqs*1This happens because ditherCopy tries to use the °dONLNd¢s⁄)È,inverse table to do color matching, but when°dONLNdœãï(ß6Tthe image is animated, the inverse table colors are limited to just black and white.°dONLNd$ó£(*To °dONLNd'ó(£⁄)Twork around the problem, you can jump into the bottlenecks and when you see the PICT°dONLNd|£ØÄ(À6hitting the opcode for °dONLNdì£ÄØ⁄)hBCopyBits, change the PICT from a srcCopy to a ditherCopy. This way°dONLNd÷ت°(◊6the dithering happens when °dONLNdÒذª⁄)â>you do the call to DrawPicture and not later on. This makes it°dONLNd0ª«.(„6:possible to use dithering and animation on the same image.
  6702. °dONLNdkflÓó*'6Rendering color PICTs in a black-and-white environment
  6703. °dONLNd¢Ó˙>* Written:°dONLNd´Ód˙à)L7/22/91°dONLNd≥˙]("6Last reviewed:°dONLNd¬˙dà)L9/17/91°dONLNd ¢(:6QI want to be able to render a color PICT as a black-and-white image substituting °dONLNd¢⁄(:¿ patterns for°dONLNd(*S(F6Bcolors. My images are pretty small and have fewer than 16 colors. °dONLNdjS*⁄(FqWhat do you suggest as the°dONLNdÖ*6S(R6 easiest way?°dONLNdí6B** ___°dONLNdñNZÍ*,One easy way is to take advantage of 32-Bit °dONLNd¬NÍZ⁄)“.QuickDraw and System 7.0’s ditherCopy transfer°dONLNdÒZf‡(Ç6%mode modifier or flag (documented in °dONLNd    Z‡f5)»Inside Macintosh°dONLNd    &Z5f⁄)U Volume VI, page 17-17). Call°dONLNd    Dfrü(é6QDrawPicture into an off-screen pixmap with the pixel depth of the original color °dONLNd    ïfür⁄(éΩ
  6704. PICT. Then°dONLNd    †r~ó(ö6call CopyBits to copy the °dONLNd    ∫ró~⁄)?pixmap to the screen, with srcCopy + ditherCopy as the transfer°dONLNd    ˙~äÇ(¶6Mmode. This will result in a nicely dithered image on the black-and-white end. ◊4◊˘
  6705. *F10)
  6706.  of 31(ÏîColor QuickDraw Q&Asˇ§◊#ˇ ˇˇˇˇ#◊ 
  6707. IR,Times
  6708. .+Z-Developer Support Center(-fi
  6709. December 1992 /X/
  6710. °dONLNd<)¥(EZKUnder System 6 without 32-Bit QuickDraw, the solution is not nearly so cut °dONLNdK¥)˛(E“and dried. One°dONLNdZ)<5m(QZ<way might be to take advantage of the fact that DrawPicture °dONLNdñ)m5˛(Qãgoes through the QuickDraw°dONLNd±5<AÈ(]Z"bottlenecks for drawing. For each °dONLNd”5ÈA˛)≠5grafproc in your PICT, you’d intercept StdBits during°dONLNd    A<Mfi(iZTDrawPicture and call your own dithering routine to examine the foreground color and °dONLNd]AfiM˛(i¸set the°dONLNdeM<Y»(uZZpen pattern or fill pattern so that it has about the same lightness as the original color.°dONLNd¿e<qü*LWell, this came out as a great sales pitch for writing a System 7-savvy app!
  6711. °dONLNd
  6712. â<òÿ*';Highlighting ignored if foreground same as background color
  6713. °dONLNdIò<§b* Written:°dONLNdRòà§¶)L8/7/91°dONLNdY§<∞Å(ÃZLast reviewed:°dONLNdh§à∞¨)L9/24/91°dONLNdpº<»f(‰Z>Under System 7, but not System 6, HiliteColor is not used for °dONLNdƺf»˛(‰Ñ!InvertRect when the hilite bit is°dONLNd–»<‘b(Z7set and the background is exactly black (R=G=B=$0000). °dONLNd»b‘˛(ÄAlso, HiliteColor doesn’t draw°dONLNd&‘<‡,(¸Z0when a pen mode of XOR is used in a LineTo call.°dONLNdW‡<ÏN* ___°dONLNd[¯<R*The °dONLNd_¯R˛)Rproblem you encounter exists whenever the background and foreground colors are the°dONLNd≤<j(,Z?same when using highlight mode. If the foreground color is the °dONLNdÒj˛(,àsame as the background color,°dONLNd<ï(8ZIhighlighting is ignored. Therefore, when you set the foreground color to °dONLNdXï˛(8≥white, you should set°dONLNdn<(è(DZHthe background color to something other than the default color of white.
  6714. °dONLNd∑@<Ob*'*Gestalt 'qdrw' selector bug and workaround
  6715. °dONLNd‚O<[b* Written:°dONLNdÎOà[¶)L8/1/91°dONLNdÚ[<gÅ(ÉZLast reviewed:°dONLNd[àg¨)L10/9/91°dONLNd    s<Ñ(õZ<Why does Gestalt tell me I have Color QuickDraw features on °dONLNdEsÑ˛(õ¢a non-Color QuickDraw°dONLNd[<ãh(ßZmachine?°dONLNddã<óN* ___°dONLNdh£<Ø≥*JThe gestaltQuickdrawFeatures ('qdrw') selector, used for determining your °dONLNd≤£≥Ø˛(À—system’s Color°dONLNd¡Ø<ª∏(◊ZSQuickDraw features, has a bug that causes it to tell you incorrectly that noncolor °dONLNdØ∏ª˛(◊÷
  6716. machines have°dONLNd"ª<«[(„Zcolor. °dONLNd)ª[«˛)XThe fix is quite simple: Gestalt has another selector, gestaltQuickdrawVersion ('qd  '),°dONLNdÇ«<”V(ÔZ8which simply returns the QuickDraw version number. This °dONLNd∫«V”˛(Ôt!version number is < gestalt8BitQD°dONLNd‹”<flƒ(˚Zfor classic QuickDraw and °dONLNdˆ”ƒfl™)à*>= gestalt8BitQD for Color QuickDraw (see °dONLNd ”™fl˛)ÊInside Macintosh°dONLNd1fl<ε(ZMVolume VI, page 3-39, for more information). The trick is to ask Gestalt for °dONLNd~flµÎ˛(”
  6717. the QuickDraw°dONLNdåÎ<˜Õ(ZPversion first; once you’ve determined that you have Color QuickDraw, the 'qdrw' °dONLNd‹ÎÕ˜˛(Î selector is°dONLNd˘<–(Z OK to use to find out specifics. ◊X◊
  6718. *ÕColor QuickDraw Q&As(Ï˙11)
  6719.  of 31ˇl◊#ˇ ˇˇˇˇ#◊ 
  6720. IR,Times
  6721. .+6-Macintosh Technical Notes /4/˘
  6722. °dONLNd)8f*'-Version 2 PICTs on pre-Color QuickDraw models
  6723. °dONLNd.8D>* Written:°dONLNd78dDà)L8/13/91°dONLNd?DP](l6Last reviewed:°dONLNdNDdPé)L10/22/91°dONLNdW\hi(Ñ6Inside Macintosh°dONLNdg\ih∑)Q Volume V says °dONLNdv\∑h⁄)N;a System 4.1 (and later) patch ensures that version 2 PICTs°dONLNd≤ht#(ê67are displayed correctly on earlier machines that don’t °dONLNdÈh#t⁄(êA!have Color QuickDraw, such as the°dONLNd tÄ(ú6-Macintosh Plus and SE. However, my version 2 °dONLNd8tÄ⁄)˘&PICT, consisting primarily of a pixmap°dONLNd_Äåa(®6C(opcode = $90 since rowBytes <8) displays correctly on a Macintosh °dONLNd¢Äaå⁄(®IIfx but displays garbage°dONLNdºåòu(¥6on a Macintosh SE.°dONLNdœò§** ___°dONLNd”∞º*+The PICT problem you reported is caused by °dONLNd˛∞º⁄)ÿ,a bug in 6.0.7 QuickDraw. The workaround for°dONLNd+º»t(‰6the time being is to:°dONLNdA‘‡Ê*+• Use System 7.0, where it’s been fixed, or°dONLNdm‡ÏO* @• Don’t use opcode $90. Instead, use padding so that opcode $98 °dONLNd≠‡OÏ⁄(mcan be used. (Opcode $98 is°dONLNd…ϯ(64the packed CopyBits version that works for rowBytes °dONLNd˝Ï¯⁄(8'>= 8.). You can do this by creating the°dONLNd%¯Å( 6picture with a pixmap °dONLNd;¯Å⁄)iIthat’s wider than you actually need, and then use the clip region to clip°dONLNdÖõ(,6out the part you don’t need.
  6724. °dONLNd¢(7Û*' GetPixelsState is slow sometimes
  6725. °dONLNd√7C>* Written:°dONLNdÃ7dCà)L8/27/91°dONLNd‘CO](k6Last reviewed:°dONLNd„CdOà)L9/24/91°dONLNdÎ[g¿(É6JWhy do I sometimes see incredible slowdowns under System 7.0 when calling °dONLNd5[¿g⁄(Éfieither°dONLNd<gs3(è66GetPixelsState or LockPixels (I’m not sure which) for °dONLNdrg3s⁄(èQthe PixMapHandle of a GWorld°dONLNdèsØ(õ6allocated in temporary memory?°dONLNdÆã** ___°dONLNd≤ó£⁄*)GetPixelsState takes an arbitrary amount °dONLNd€ó⁄£⁄)¬5of time since it makes a call to RecoverHandle to get°dONLNd£Ø (À6\the handle pointing to the baseaddr. Therefore, the slowdown you see as actually due to the °dONLNdm£ Ø⁄(ÀËcall°dONLNdrتÖ(◊6Jto RecoverHandle, which is slow because it must traverse the heap to find °dONLNdºØÖª⁄(◊£the pointer to the°dONLNdœª«x(„6Ibaseaddr. LockPixels is not responsible for the slowdown because it does °dONLNdªx«⁄(„ñnot make call to any°dONLNd-«”ˇ(Ô61traps that could take an extended amount of time.
  6726. °dONLNd_Î˙6*'(OpenCPicture and PICTs other than 72 dpi
  6727. °dONLNdà˙>* Written:°dONLNdë˙dà)L10/2/91°dONLNdô](.6Last reviewed:°dONLNd®dà)L10/8/91°dONLNd∞*Œ(F6\Can I use OpenCPicture to create PICTs with a higher resolution than 72 dots per inch (dpi)?°dONLNd
  6728. *6$* __°dONLNdBNJ*=There’s good news and bad news: The good news is that you’re °dONLNdMBJN⁄(jhon top of the situation, which°dONLNdlNZ%(v6:means the bad news is that there aren’t better ways to do °dONLNd¶N%Z⁄(vC#what you want to do, mostly. Here’s°dONLNd ZfH(Ç6
  6729. the scoop:°dONLNd’r~*2You can use vRes and hRes in pictures opened with °dONLNdr~⁄)¯)OpenCPicture to tell QuickDraw it’s not a°dONLNd1~ä—(¶6Z72-dpi picture, and as long as the application that receives the picture uses DrawPicture °dONLNdã~—ä⁄(¶Ôto°dONLNdéäñw(≤6Eimage it, QuickDraw will Do The Right Thing—scaling it on the screen °dONLNd”äwñ⁄(≤ïto 72 dpi instead of°dONLNdËñ¢’(æ6[making it humongously large. Unfortunately, this way you lose hairlines; if you print such °dONLNd    Cñ’¢⁄(æÛa ◊4◊˘
  6730. (Ï612)
  6731.  of 31(ÏîColor QuickDraw Q&Asˇ◊#ˇ ˇˇˇˇ#◊ 
  6732. IR,Times
  6733. .+Z-Developer Support Center(-fi
  6734. December 1992 /X/
  6735. °dONLNd<)Ë(EZ'picture to a 72-dpi grafPort (like the °dONLNd'Ë)˛)¨:LaserWriter driver normally returns), you’ll get 1/72-inch°dONLNdb)<5?(QZ7lines instead of 1/300-inch lines as you probably want.°dONLNdöA<MX*(This °dONLNd†AXMh)can°dONLNd£AhM⁄) work correctly, but the °dONLNdºA⁄M˛)r?receiving application has to notice that your picture is bigger°dONLNd¸M<YS(uZthan °dONLNdMSY˛)Y72 dpi and ask PrGeneral to increase the resolution of the printing grafPort accordingly,°dONLNd[Y<e(ÅZ)and this doesn’t always or often happen.)
  6736. °dONLNdÖ}<åu*'+No System 7 QuickDraw alpha channel support
  6737. °dONLNd±å<òb* Written:°dONLNd∫åàò≤)L10/23/91°dONLNd√ò<§Å(¿ZLast reviewed:°dONLNd“òà§≤)L11/27/91°dONLNd€∞<ºZ(ÿZ:How can I directly access the alpha channel (the unused 8 °dONLNd∞Zº˛(ÿx#bits in a 32-bit direct pixel using°dONLNd9º<»Ω(‰ZQuickDraw) under System °dONLNdQºΩ»˛)Å>7? Under System 6 it was easy, but under System 7’s CopyBits()°dONLNdê»<‘U(Z9the alpha channel works with srcXor but not with srcCopy.°dONLNd ‘<‡N* ___°dONLNdŒÏ<¯©*HWith the System 7.0 QuickDraw rewrite, all “accidental” support for the °dONLNdÏ©¯˛(«unused byte was°dONLNd&¯<Ô( Z"removed, because QuickDraw is not °dONLNdH¯Ô˛)≥5supposed to operate on the unused byte of each pixel.°dONLNd~<•(,ZQuickDraw has never °dONLNd핲)iHofficially supported use of the extra byte for such purposes as an alpha°dONLNd€<°(8Zchannel. As stated in °dONLNdÒ°Ú)eInside Macintosh°dONLNdÚ)Q Volume °dONLNd    ˛)+0VI, page 17-5, “8 bits in the pixel are not part°dONLNd:<(‚(DZ!of any component. These bits are °dONLNd[‚(˛)¶6unused: Color QuickDraw sets them to 0 in any image it°dONLNdí(<4n(PZ creates. If °dONLNdû(n4˛)2Npresented with a 32-bit image—for example, in the CopyBits procedure—it passes°dONLNdÌ4<@Ø(\Zwhatever bits are there.”°dONLNdL<X *RTherefore, you cannot rely on any QuickDraw procedure to preserve the contents of °dONLNdYL X˛(tË
  6738. the unused°dONLNddX<d∏(ÄZbyte, which in your case °dONLNd}X∏d˛)|Bis the alpha channel. In fact, even CopyBits may alter the byte if°dONLNd¿d<p:(åZ7stretching or dithering is involved in the CopyBits by °dONLNd˜d:p˛)˛)setting them to zero. Therefore, the only°dONLNd!p<|ó(òZIpossible workarounds for this problem are to not use the unused byte for °dONLNdjpó|˛(òµalpha channel storage°dONLNdÄ|<àL(§Z=since the integrity of the data cannot be guaranteed; or, to °dONLNdΩ|Là˛(§j"not use QuickDraw drawing routines°dONLNd‡à<î‘(∞Z which can alter the unused byte.
  6739. °dONLNd¨<ª[*'$BitsToRgn and MPW BitMapToRegionGlue
  6740. °dONLNd&ª<«b* Written:°dONLNd/ªà«≤)L10/29/91°dONLNd8«<”Å(ÔZLast reviewed:°dONLNdG«à”≤)L12/11/91°dONLNdPfl<Î
  6741. (Z%Which version of the system software °dONLNdufl
  6742. β)Œ.first contained the call BitsToRgn? Is there a°dONLNd§Î<˜µ(ZPworkaround for this call if my users have an earlier version of system software?°dONLNdı˜<N* ___°dONLNd˘<«*The call BitmapToRegion °dONLNd«˛)ã5was introduced with 32-Bit QuickDraw and became fully°dONLNdG<'“(CZdocumented in Volume VI of °dONLNdb“'))ñInside Macintosh,°dONLNds)'])W
  6743.  which is °dONLNd}]'˛)4primarily System 7 information.°dONLNdù'<3p(OZ    However, °dONLNd¶'p3˛)4Ksince the differences between System 7’s QuickDraw and 32-Bit QuickDraw are°dONLNdÚ3<?»([Zminor, most of System 7’s °dONLNd     3»?˛)å<QuickDraw routines are available in system software prior to°dONLNd    I?<K(gZ+System 7.0 using the 32-bit QuickDraw INIT.°dONLNd    uW<cj*    To check °dONLNd    ~Wjc˛).Rto see if a system contains 32-bit QuickDraw, you can use the following snippet of°dONLNd    —c<oU(ãZcode:,
  6744. Courier
  6745.     °dONLNd    ◊{<Üï*E    /* Find out if GWorlds and CQD are implemented on this machine */°dONLNd
  6746. Ö<êr*
  6747. >    (void) Gestalt (gestaltQuickdrawVersion, /*<*/&qdVersion);°dONLNd
  6748. \è<ö;*
  6749. 3    gHasGWorlds = (qdVersion > gestaltOriginalQD &&°dONLNd
  6750. ëô<§*
  6751. -                   qdVersion < gestalt8BitQD)°dONLNd
  6752. ø£<Æ1*
  6753. 1                  || qdVersion >= gestalt32BitQD; ◊X◊
  6754. *"Color QuickDraw Q&As(Ï˙13)
  6755.  of 31ˇ@◊#ˇ ˇˇˇˇ#◊ 
  6756. IR,Times
  6757. .+6-Macintosh Technical Notes /4/˘
  6758. °dONLNd)5ü*$OIf you are using MPW as a development platform, MPW has a library call you can °dONLNdO)ü5⁄(QΩ
  6759. use that will°dONLNd]5Aã(]6Kallow you to use the routine regardless of whether or not 32-bit QuickDraw °dONLNd®5ãA⁄(]©exists. The glue°dONLNdπAMO(i6?routine is called BitMapToRegionGlue() and is available to MPW °dONLNd¯AOM⁄(imusers. Substitute this call for°dONLNdMYÔ(u6,BitMapToRegion calls and the glue code will °dONLNdDMÔY⁄)◊2take care of patching in the proper code if 32-bit°dONLNdwYe|(Å6QuickDraw does not °dONLNdäY|e⁄)dHexist. If you’re using Think C, you can use the oConv utility to convert°dONLNd”eq(ç61the MPW object file into a Think C usable format.
  6760. °dONLNdâòB*'+Ensuring even rowBytes for 'cicn' resources
  6761. °dONLNd1ò§>* Written:°dONLNd:òd§à)L12/4/91°dONLNdB§∞](Ã6Last reviewed:°dONLNdQ§d∞à)L1/27/92°dONLNdYº»í(‰6PIs there any way to force bitmaps and masks within a 'cicn' resource to have an °dONLNd©ºí»⁄(‰∞
  6762. even rowBytes°dONLNd∑»‘(62(using ResEdit)? I want to avoid duplicating icon °dONLNdÈ»‘⁄)Í(bitmaps—one for color systems set to B&W°dONLNd‘‡,(¸6and °dONLNd‘,‡⁄)Qone for B&W systems—to reduce program size as well as development and maintenance°dONLNdh‡Ï´(6Ycosts. The bitmaps in the 'cicn' can also be sized specifically to the task, whereas the °dONLNd¡‡´Ï⁄(…old B&W°dONLNd…ϯê(6icons are of a fixed size °dONLNd„Ïê¯⁄)xBand contain no sizing information. It’s simple enough to read in a°dONLNd&¯≈( 6#'cicn' and extract the bitmap. The °dONLNdI¯≈⁄)≠3problem is that on a 68000 (no Color QuickDraw), if°dONLNd}Ô(,6-rowBytes is odd, an odd address trap results.°dONLNd´** ___°dONLNdØ(4**<There isn’t any way to get ResEdit itself to create bitmaps °dONLNdÎ(*4⁄(PH#with even rowBytes for 8 x 8 'cicn'°dONLNd4@÷(\6(resources, but here are few suggestions:°dONLNd8LXå*You could process your °dONLNdOLåX⁄)tF'cicn' resources first, so that they have bitmaps as you require them.°dONLNdñXdµ(Ä6UTo alter the resource with a quick little program would be trivial, especially given °dONLNdÎXµd⁄(Ä”that the°dONLNdÙdpÔ(å6/bitmap data sits last in the 'cicn'. All you’d °dONLNd#dÔp⁄)◊-need to do is expand the bitmap image data by°dONLNdQp|ü(ò6Qpadding each line to an even length and then changing the rowBytes value. Or you °dONLNd¢pü|⁄(òΩ could de-rez°dONLNdØ|à    (§66the 'cicn's and patch them with a text editor, either °dONLNdÂ|    à⁄)Ò+by hand or with a search-and-replace script°dONLNdàîZ(∞6
  6763. of some kind.
  6764. °dONLNd¨ª∏*';CopyBits blend mode: OpColor’s affect & eliminating banding
  6765. °dONLNd[ª«>* Written:°dONLNddªd«é)L12/11/91°dONLNdm«”](Ô6Last reviewed:°dONLNd|«d”à)L2/17/92°dONLNdÑflΗ(6_I have two gray-colored pixmaps that I wish to blend together; one is on the screen, the other °dONLNd„fl—Î⁄(Ôin°dONLNdÊΘã(6Oan off-screen pixmap. I use CopyBits to copy the off-screen to the screen, but °dONLNd5Îã˜⁄(©it does not seem°dONLNdF˜å(6Qto blend them. Instead, it seems to match the colors of the screen bitmap to the °dONLNdó˜å⁄(™closest colors in°dONLNd© (+63some table, thus having the effect of reducing the °dONLNd‹ ⁄)Ù(number of colors displayed on the screen°dONLNd    ì(76bitmap. Any suggestions?°dONLNd    '** ___°dONLNd    "3?«*\There are two distinct questions here: 1) Why ain’t it blending? and 2) What’s this banding °dONLNd    ~3«?⁄([Âfor?°dONLNd    É?K§(g6The first problem is almost °dONLNd    ü?§K⁄)å>certainly because OpColor isn’t set properly. This is a third,°dONLNd    fiKW¶(s6implicit, operand on several °dONLNd    ˚K¶W⁄)é>arithmetic graphics operations, including blend. For blend, it°dONLNd
  6766. :Wcõ(6Qdescribes the proportions to mix the source and destination colors in the blend. °dONLNd
  6767. ãWõc⁄(π For an equal°dONLNd
  6768. òcol(ã6mix, you should °dONLNd
  6769. ®clo⁄)TIset this color to a halfway gray. (Call OpColor() with a color where red,°dONLNd
  6770. Úo{∑(ó6"green, and blue all equal $8000.) °dONLNd o∑{⁄)ü=This effect is described in the description of the blend mode°dONLNd R{á((£6on °dONLNd U{(ác) page 60 of °dONLNd `{cá∂);Inside Macintosh°dONLNd p{∂á⁄)S: Volume V. Unfortunately, the initial value for OpColor is°dONLNd ´áì^(Ø6Dblack (0,0,0), so you were seeing no mixing of your off-screen data. ◊4◊˘
  6771. *=14)
  6772.  of 31(ÏîColor QuickDraw Q&AsˇÜ◊#ˇ ˇˇˇˇ#◊ 
  6773. IR,Times
  6774. .+Z-Developer Support Center(-fi
  6775. December 1992 /X/
  6776. °dONLNd<)¢(EZIThe second half of your question is why you’re getting a banding effect. °dONLNdI¢)˛(E¿(When you fix the°dONLNd[)<5µ(QZNabove problem, you’ll still get banding.) Unfortunately, the arithmetic modes °dONLNd©)µ5˛(Q”are constrained°dONLNdπ5<AΩ(]ZQby the size of the inverse table. As your screen no doubt uses the default 4-bit °dONLNd
  6777. 5ΩA˛(]€inverse table,°dONLNdA<M∞(iZNyou’ll find that you’ll get only 2^4 = 16 levels of gray. If you enlarge your °dONLNdgA∞M˛(iŒscreen’s inverse°dONLNdxM<YU(uZ>table to 5 bits, the maximum allowable, you’ll still only get °dONLNd∂MUY˛(us$32 gray levels. (To do this, set the°dONLNd€Y<e◊(ÅZgdResPref field in the GDevice °dONLNd˙Y◊e˙)õ:to 5, then call MakeITable().) The only way to get a fully°dONLNd4Y˙e˛(Å-°dONLNd5e<q‹(çZ$gradual, great-looking effect is to °dONLNdYe‹q˛)†;do all the work off-screen in 24-bit deep pixmaps, and then°dONLNdïq<}_(ôZcopy it °dONLNdùq_}˛)#Vto the screen. Because they can operate directly on colors, rather than having to work°dONLNdÙ}<âÒ(•Z\through the intermediary of color indices, direct pixmaps are not limited by inverse tables °dONLNdP}Òâ˛(•(in°dONLNdTâ<ïj(±Z?fact, they don’t even have real inverse tables). You could use °dONLNdìâjï˛(±à16-bit pixmaps, but they only°dONLNd±ï<°¸(ΩZ)provide 32 grays (having only 5 bits for °dONLNd⁄︰˛)¿4each component), so this wouldn’t be any better than°dONLNd°<≠Ú(…Z)increasing the size of the inverse table.
  6778. °dONLNd9≈<‘_*'(Icon dimming under System 7 and System 6
  6779. °dONLNdb‘<‡b* Written:°dONLNdk‘à‡¶)L1/6/92°dONLNdr‡<ÏÅ(ZLast reviewed:°dONLNdŇà϶)L2/6/92°dONLNdà¯<ı( Z%When you bring up the Control Panels °dONLNd≠¯ı˛)π3window under System 7 on a color system and click a°dONLNd·<∂(,ZUcontrol panel item icon, it paints itself that fancy gray. How can I get that effect?°dONLNd7<N* ___°dONLNd;(<4©*DTo get the fancy System 7 icon dimming to work in your program, use °dONLNd(©4˛(P«the icon drawing°dONLNdê4<@f(\Z    routines °dONLNdô4f@˛)*NPlotIconID or PlotCIconHandle with an IconTransformType of ttSelected. Both of°dONLNdË@<L¨(hZthese routines and their °dONLNd@¨L˛)pFtransform types are used by the control panel and are described in the°dONLNdHL<Xg(tZ:Macintosh Technical Note “Drawing Icons the System 7 Way.”°dONLNdÉd<pv* If you want °dONLNdèdvp˛):Othe same effect under System 6, you’ll have to emulate the dimming of the icons°dONLNdflp<|U(òZ<via QuickDraw, by installing a color search proc to dim the °dONLNdpU|˛(òs!RGB values that the icon uses. On°dONLNd=|<àz(§Z page 146 of °dONLNdI|zàõ)>Inside °dONLNdP|õàÃ)!    Macintosh°dONLNdY|Ãà˛)1< Volume V is a description of how to define and install your°dONLNdñà<îõ(∞Zcustom search proc.
  6780. °dONLNd™¨<ª‘*'8QuickDraw out of memory if debugger invoked by “Jackson”
  6781. °dONLNd„ª<«b* Written:°dONLNdϪ૨)L3/11/92°dONLNdÙ«<”Å(ÔZLast reviewed:°dONLNd«à”¶)L4/7/92°dONLNd
  6782. fl<ÎÃ(ZI am getting a strange bug in °dONLNd(flÃβ)ê:which the Macintosh debugger is being invoked by an A-trap°dONLNdcÎ<˜Å(ZDmarked “Jackson” when I call SetCCursor in certain situations and a °dONLNdßÎز(üsecond monitor is hooked°dONLNd¿˜<¿(ZSup. The cursor structure being passed appears to be valid. I’ve also been crashing °dONLNd    ˜¿˛(fi unexpectedly°dONLNd     <}(+ZCin this same spot for the past few weeks. I assume Jackson is some °dONLNd    c}˛(+õkind of error assertion that°dONLNd    Ä<V(7Z8was left in System 7’s Color QuickDraw code. What gives?°dONLNd    π<'N* ___°dONLNd    Ω3<?ú*Jackson was a code °dONLNd    –3ú?˛)`Iname for 32-Bit QuickDraw. The trap you refer to is in fact never called;°dONLNd
  6783. ?<K¡(gZSit’s not supposed to be encountered by you ever. The trap is reserved for Apple to °dONLNd
  6784. m?¡K˛(gfl
  6785. use in future°dONLNd
  6786. {K<W(sZ,versions of Color QuickDraw. If you examine °dONLNd
  6787. ßKW˛)›.the code directly preceding the _Debugger, you°dONLNd
  6788. ÷W<c≥(Zwill notice that it is doing,
  6789. Courier
  6790.     °dONLNd
  6791. Ûo<zæ*        MOVEQ      #$19,D0°dONLNd y<Ñ»*
  6792.         JSR        ([$1524])
  6793. °dONLNd +è<õØ*which for you and me is ◊X◊
  6794. *5Color QuickDraw Q&As(Ï˙15)
  6795.  of 31ˇ
  6796. ‚◊#ˇ ˇˇˇˇ#◊ 
  6797. IR,Times
  6798. .+6-Macintosh Technical Notes /4/˘,
  6799. Courier
  6800.     °dONLNd(S*?         MoveQ #25,D0                ; say that memory is full…°dONLNd@'20*
  6801. 8        _SysError                    ; and call syserror
  6802. °dONLNdy=I¶*the line following would be...
  6803.     °dONLNdòU`ä*J        _Debugger ; Hey! sysError came back! Better drop into the debugger
  6804. °dONLNd„kw¬*%What’s all this tell you? You have a °dONLNdk¬w⁄)™;debugger installed that is rts’ing from the SysError vector°dONLNdDwÉ(ü6-(you aren’t supposed to return from SysError °dONLNdqwÉ⁄)Ë)normally), or you have installed your own°dONLNdõÉèq(´6GSysError vector which is rts’ing. At any rate, if you examine the code °dONLNd‚Éqè⁄(´èdirectly following the°dONLNd˘èõ∂(∑6 debugger statement and see what °dONLNdè∂õ⁄)û:it does, you might imagine the source code looks something°dONLNdTõß@(√6
  6805. like this:
  6806.     °dONLNd_≥æl*DMemFull       MoveQ #25,D0              ; say that memory is full...°dONLNd§Ω»?*
  6807. ;              _SysError                 ; and call syserror°dONLNd‡«“î*
  6808. L; If it returns better go into the debugger since its not supposed to return°dONLNd-—‹b*
  6809. B              _Debugger                 ; Hey! sysError came back!°dONLNdp€Ê*
  6810. ;°dONLNdrÂê*
  6811. CallNewHand   _NewHandle°dONLNdãÔ˙î*
  6812. L              bne.S  MemFull            ; could not get the memory, just die°dONLNdÿ˘m*
  6813.               rts
  6814. °dONLNdÍw*What’s happening °dONLNd˚w⁄)_Ais that you’re running out of memory somehow (several places call°dONLNd='—(C6'MemFull, not just the above place), so °dONLNdd—'⁄)π5you’d need to use a stack crawl to figure out how you°dONLNdö'3i(O6Egot there. But, the bottom line, QuickDraw has run out of memory and °dONLNdfl'i3⁄(Oácannot continue; it tried°dONLNd˘3?([65to put up a system error dialog to tell the user and °dONLNd.3?⁄)¯'for some reason the machine did not get°dONLNdV?K§(g6Prestarted and the SysError vector returned. You are now in your debugger, since °dONLNd¶?§K⁄(g¬    QuickDraw°dONLNd∞KW4(s6=put up the system error dialog because it could not continue.
  6815. °dONLNdÓo~ú*'6ditherCopy not supported on LaserWriter or ImageWriter
  6816. °dONLNd%~ä>* Written:°dONLNd.~däà)L5/31/91°dONLNd6äñ](≤6Last reviewed:°dONLNdEädñà)L11/6/91°dONLNdM¢Æ•( 6OditherCopy is not supported on LaserWriters or ImageWriters. On a LaserWriter, °dONLNdú¢•Æ⁄( √
  6817. ditherCopy°dONLNd߯∫(÷61gets misinterpreted and inverts the image. On an °dONLNdÿÆ∫⁄)Ó*ImageWriter it’s treated as a srcCopy. The°dONLNd∫Δ√(‚6TImageWriter driver doesn’t support color grafPorts, which is the only way to do the °dONLNdW∫√Δ⁄(‚·pixel°dONLNd]Δ“d(Ó6Eimage required for ditherCopy. Use srcCopy instead for both printers. ◊4◊˘
  6818. *˛16)
  6819.  of 31(ÏîColor QuickDraw Q&Asˇ¯◊#ˇ ˇˇˇˇ#◊ 
  6820. IR,Times
  6821. .+Z-Developer Support Center(-fi
  6822. December 1992 /X/
  6823. °dONLNd)<8Á(TZ;Macintosh Color QuickDraw CalcCMask and SeedCFill clarified
  6824. °dONLNd<8<Db* Written:°dONLNdE8àD¶)L1/1/90°dONLNdLD<PÅ(lZLast reviewed:°dONLNd[DàP≤)L11/21/90°dONLNdd\<hÆ(ÑZHI’m having trouble using CalcCMask and SeedCFill. What am I doing wrong?°dONLNd≠h<tN* ___°dONLNd±Ä<å,*-There is some confusion regarding the use of °dONLNdfiÄ,å˛)&the Macintosh Color QuickDraw routines°dONLNdå<ò0(¥Z0CalcCMask and SeedCFill, which are analogous to °dONLNd5å0ò˛)Ù(the older CalcMask and SeedFill. Much of°dONLNd^ò<§L(¿Z8the confusion was caused by early documentation errors. °dONLNdñòL§˛(¿j$Be sure you have the release version°dONLNdª§<∞á(ÃZof Volume 5 of °dONLNd §á∞ÿ)KInside Macintosh°dONLNd⁄§ÿ∞Ã)Q5 and version 2.0 or later of the MPW interface files.°dONLNdº<»ı(‰Z'The correct interface for CalcCMask is:,
  6825. Courier
  6826.     °dONLNd8‘<fl*-PROCEDURE CalcCMask(srcBits, dstBits: BitMap;°dONLNdffi<È·*
  6827. !          srcRect, dstRect: Rect;°dONLNdàË<Û‹*
  6828.            seedRGB:     RGBColor;°dONLNd©Ú<˝‹*
  6829.            matchProc:    ProcPtr;°dONLNd ¸<·*
  6830. !          matchData:    LongInt);
  6831. °dONLNdÏ<Ì*'The correct interface for SeedCFill is:
  6832.     °dONLNd*<5*-PROCEDURE SeedCFill(srcBits, dstBits: BitMap;°dONLNdB4<?·*
  6833. !          srcRect, dstRect: Rect;°dONLNdd><IÊ*
  6834. "          seedH, seedV:   INTEGER;°dONLNdáH<S»*
  6835.           matchProc:    Ptr;°dONLNd§R<]·*
  6836. !          matchData:    LongInt);
  6837. °dONLNdΔh<t˚*'Each routine calculates a one-bit deep °dONLNdÌh˚t˛)ø4bitmap representing either the mask or the fill area°dONLNd"t<Ģ(úZWdepending upon the routine. In both cases, the source bitmap may be either a bitmap or °dONLNdyt˘Ä˛(úa°dONLNd{Ä<å—(®ZVpixmap, but the destination must be a bitmap, because it must have a depth of one-bit.°dONLNd“ò<§•*It is difficult to pass a °dONLNdÏò•§˛)iEpixmap for the source parameter because of Pascal’s type checking. To°dONLNd2§<∞9(ÃZ7get around this difficulty, you can declare a new type:
  6838.     °dONLNdjº<«æ*     BitMapPtr  =  ^BitMap
  6839. °dONLNdÖ“<fi*,then use it to coerce the pixmap as follows:
  6840.     °dONLNd≤Í<ı*+     SeedCFill(BitMapPtr(@myPixMap)^, ...);
  6841. °dONLNdfi< *-If you have a PixMapHandle, do the following:
  6842.     °dONLNd <#1*1     SeedCFill(BitMapPtr(myPixMapHandle^)^, ...);
  6843. °dONLNd>.<:G*8If you are using a grafPort (or a window), you can pass °dONLNdv.G:˛(Ve"myWindow^.portBits and not have to°dONLNdô:<FH(bZ7worry about whether the port uses a bitmap or a pixmap.°dONLNd—R<^;*8Most of the other parameters are explained in detail in °dONLNd    R;^ë)ˇInside Macintosh.°dONLNdRë^˛)V To use the matchProc°dONLNd0^<j{(ÜZ@and the matchData parameters, though, you need more information.°dONLNdqv<Çv*
  6844. As stated in °dONLNd~vvÇÀ):Inside Macintosh,°dONLNdèvÀÇê)U+ the matchProc parameter is a pointer to a °dONLNd∫vêDz)≈routine that you would°dONLNd—Ç<é÷(™ZYlike to use as a custom SearchProc. To better understand how this is used, it is helpful °dONLNd*Ç÷é˛(™Ùto know°dONLNd2é<ö(∂Z*how SeedCFill and CalcCMask actually work. ◊X◊
  6845. *6Color QuickDraw Q&As(Ï˙17)
  6846.  of 31ˇÓ◊#ˇ ˇˇˇˇ#◊ 
  6847. IR,Times
  6848. .+6-Macintosh Technical Notes /4/˘
  6849. °dONLNd)»*ZBoth routines start by creating a temporary bitmap which, by definition, is one bit deep. °dONLNdZ»)⁄(EÊThe°dONLNd^)5q(Q6source pixmap (or °dONLNdp)q5⁄)YHbitmap) is then copied to the temporary bitmap using CopyBits. This copy°dONLNdπ5A˝(]6/causes the image to be converted to a depth of °dONLNdË5˝A⁄)Â*one-bit. Now with a normal black-and-white°dONLNdAM…(i6\image, the standard CalcMask or SeedFill routine is used to generate the destination bitmap.°dONLNdpYeä*OMost of the real work is done in the original call to CopyBits, which maps the °dONLNdøYäe⁄(Å®pixmap image to°dONLNdœeq«(ç6Wa monochrome bitmap equivalent. For each color in the source pixmap, CopyBits will map °dONLNd&e«q⁄(çÂit to°dONLNd,q}M(ô6@either black or white. Which colors map to black and which ones °dONLNdlqM}⁄(ôkto white is determined by the°dONLNdä}âR(•6 SearchProc.°dONLNdñï°*2SeedCFill installs a default SearchProc that maps °dONLNd»ï°⁄)Í/all colors to black except for the color of the°dONLNd¯°≠π(…6\pixel at (seedH,seedV). SeedFill then calculates as usual the fill mask for the white bits .°dONLNdUπ≈**The default SearchProc for CalcCMask maps °dONLNdπ≈⁄)ÿ2all colors to white except the color passed in the°dONLNd≤≈—ô(Ì6JseedRGB parameter. The seedRGB parameter, then, would be the color of the °dONLNd¸≈ô—⁄(Ì∑
  6850. item that you°dONLNd
  6851. —›o(˘6wanted to “lasso.”°dONLNdÈıÆ*UBut suppose you want to fill over all colors that were shades of green, not just the °dONLNdrÈÆı⁄(Ã
  6852. particular°dONLNd}ıM(6@shade of green at (seedH,seedV). Or maybe you want to fill over °dONLNdΩıM⁄(k all colors that are lighter than°dONLNdfi
  6853. L()6 50 percent °dONLNdÈL
  6854. ⁄)4Nbrightness. Or maybe you want to use dark colors as edge colors for CalcCMask.°dONLNd8
  6855. I(56:To do such things, you need to pass a pointer to your own °dONLNdr
  6856. I⁄(5gSearchProc in the matchProc°dONLNdé%J(A6
  6857. parameter.°dONLNdô1=Q*ABecause your matchProc is just a custom search procedure for the °dONLNd⁄1Q=⁄(YoColor Manager, it should be°dONLNdˆ=I‰(e6$declared as one, but Volumes I–V of °dONLNd=‰I)ÃInside °dONLNd!=I9)$    Macintosh°dONLNd*=9I⁄)1 have documented this routine°dONLNdHIUu(q6Kincorrectly. The correct declaration for a custom SearchProc is as follows:,
  6858. Courier
  6859.     °dONLNdîal÷*&FUNCTION SearchProc(VAR RGB: RGBColor;°dONLNdªkvÂ*
  6860. )          VAR result: LongInt) : Boolean;
  6861. °dONLNdÂÅç™*Normally, as each SearchProc °dONLNdÅ™ç⁄)íAis installed, it is added to the head of the SearchProc chain, so°dONLNdDçôó(µ6Sthat it is called before all of the other ones that were already installed. When a °dONLNdóçóô⁄(µµ
  6862. SearchProc is°dONLNd•ô•Ã(¡6)installed, it can do one of three things:°dONLNdœ±Ω6*51. Completely ignore the call by returning FALSE and °dONLNd±6Ω⁄(ŸTnot modifying any of the input°dONLNd#Ω…N(Â6 parameters;°dONLNd/…’4* >2. Completely handle the call by setting the result parameter °dONLNdm…4’⁄(ÒR$to be the index into the color table°dONLNdí’·<(˝6=that matches (according to your rules) the RGB parameter. In °dONLNdœ’<·⁄(˝Z!that case, the SearchProc returns°dONLNdÒ·Ì:(    6TRUE;°dONLNd˜Ì˘ß* R3. Partially handle the call by modifying the RGB parameter, then returning FALSE.°dONLNd    Já*HIn cases 1 and 3, the Color Manager continues down the SearchProc chain °dONLNd    íá⁄(-•until it finds one°dONLNd    •R(96
  6863. that returns °dONLNd    ≤R⁄):OTRUE. If none of the custom routines handle the call, then the built-in default°dONLNd
  6864. )·(E6+routine is used. In case 3, you can change °dONLNd
  6865. -·)⁄)…1the RGB color that is being matched. For example,°dONLNd
  6866. _)5æ(Q6Qif you want all shades of green to map to pure green, modify the RGB color, then °dONLNd
  6867. ∞)æ5⁄(Q‹return°dONLNd
  6868. ∑5Aí(]6QFALSE, letting the Color Manager find the index of that green in the color table.°dONLNd     MYK*BIn case 2, you return TRUE to indicate that you handled the call, °dONLNd KMKY⁄(uiand you return the color table°dONLNd jYe#(Å66index in the result parameter. The Color Manager then °dONLNd †Y#e⁄(ÅA$uses that index. For example, if you°dONLNd ≈eqT(ç6Fwant to substitute white for all colors that can’t be matched exactly °dONLNd eTq⁄(çrin the color table, then each°dONLNd )q}0(ô6time °dONLNd .q0}⁄)Xyou get called you either return the index into the color table of the exact color, or 0°dONLNd á}â(•64(which is the index for white) for all other colors.°dONLNd ºï°H*    A custom °dONLNd ≈ïH°⁄)0LSearchProc for SeedCFill and CalcCMask should always return TRUE because the°dONLNd
  6869. °≠>(…6default °dONLNd
  6870. °>≠⁄)&JColor Manager SearchProc usually doesn’t make sense. Because SeedCFill and ◊4◊˘
  6871. (Ï618)
  6872.  of 31(ÏîColor QuickDraw Q&Asˇ◊#ˇ ˇˇˇˇ#◊ 
  6873. IR,Times
  6874. .+Z-Developer Support Center(-fi
  6875. December 1992 /X/
  6876. °dONLNd<)ò(EZHCalcCMask are using CopyBits to copy to a 1-bit bitmap, you need to set °dONLNdHò)˛(E∂the result to be either°dONLNd`)<5p(QZ 0 or 1 (the °dONLNdl)p5˛)4Uonly possible values in a 1-bit bitmap). A result of 0 is white, and a result of 1 is°dONLNd¬5<AY(]Zblack.°dONLNd…M<Y∞*All colors for SeedCFill °dONLNd‚M∞Y˛)tFthat should be “filled over” would generate a result of 0 (white), and°dONLNd)Y<e(ÅZ4all colors that stop the fill generate a 1 (black). °dONLNd]Ye˛)›3SeedFill is then called to fill the white area. All°dONLNdëe<qÒ(çZ[colors for CalcCMask that you want to form boundaries should generate results of 1 (black).°dONLNdÌ}<â[*/When your SearchProc gets called, the gdRefCon °dONLNd}[â˛(•yfield of the current GDevice°dONLNd9â<ïÑ(±ZC(theGDevice^^.gdRefCon) contains a pointer to the following record:,
  6877. Courier
  6878.     °dONLNd}°<¨Ø*    matchRec  =  RECORD°dONLNdï´<∂π*
  6879.       red:       Integer;°dONLNdص<¿π*
  6880.       green:     Integer;°dONLNd…ø< π*
  6881.       blue:      Integer;°dONLNd„…<‘π*
  6882.       matchData: LongInt;°dONLNd˝”<fid*
  6883.     END;
  6884. °dONLNdÈ<ıà*DThe red, green, and blue parameters for SeedCFill are the values of °dONLNdJÈàı˛(¶the color of the pixel at°dONLNddı<x(Z;(seedH,seedV). For CalcCMask, they are the fields from the °dONLNdüıx˛(ñseedRGB parameter. Your°dONLNd∑<
  6885. ()Z.SearchProc can use this information to decide °dONLNdÂ
  6886. ˛)·-which colors are “fill-over” colors and which°dONLNd
  6887. <À(5Zcolors are “boundary” colors. °dONLNd1
  6888. À˛)è<For example, if you always set (seedH,seedV) to be the mouse°dONLNdn<%[(AZpoint, °dONLNdu[%˛)Wyour SearchProc then bases its decisions using the color of the pixel under the cursor.°dONLNdÕ%<1Δ(MZVFor example, the user clicks a shade of green, so all shades of green get filled over.°dONLNd$=<I‚*!The matchData field contains the °dONLNdE=‚I˛)¶5value that you passed into the SeedCFill or CalcCMask°dONLNd{I<UF(qZ5routines in the matchData parameter. The use of this °dONLNd∞IFU˛(qd%field is completely user-defined. For°dONLNd÷U<aQ(}Z9example, since your SearchProc routine may be a separate °dONLNdUQa˛(}o"module, you might want to use this°dONLNd2a<mfi(âZVfield to pass a handle to your variables. This field can contain a handle, a pointer, °dONLNdàafim˛(â¸a long°dONLNdèm<yi(ïZCinteger, or whatever; or you can just ignore this field altogether.°dONLNd”Ö<ëΩ*JWarning: There are some features of CalcCMask and SeedCFill you should be °dONLNdÖΩë˛(≠€ aware of. To°dONLNd*ë<ù(πZ-understand them, you should be familiar with °dONLNdWëù˛)·+the use of CalcMask and SeedFill, which are°dONLNdÉù<©Ù(≈Z&described in the QuickDraw chapter of °dONLNd©ùÙ©E)∏Inside Macintosh°dONLNdπùE©Ä)Q  Volume IV.°dONLNd≈µ<¡å(›ZCalcCMask and °dONLNd”µå¡˛)PJSeedCFill both use a parameter set that is very similar to the one used by°dONLNd¡<Õ∂(ÈZCopyBits. CalcMask and °dONLNd5¡∂Õ˛)zDSeedFill, however, are a different story. Instead of passing bitmaps°dONLNdzÕ<Ÿé(ıZand rectangles to °dONLNdåÕéŸ˛)RKSeedFill and CalcMask, these routines use an unusual set of parameters that°dONLNdÿŸ<™(ZMdescribe the memory to be operated upon in terms of pointers, height, width, °dONLNd    %Ÿ™Â˛(»and offsets to the°dONLNd    8Â<Ò,(
  6889. Z/next row (rowBytes). Although these parameters °dONLNd    gÂ,Ò˛),are fairly easy to calculate, there are some°dONLNd    îÒ<˝q(Z limitations.°dONLNd    °    <À* The most restrictive limitation °dONLNd    ¡    À˛)è@is that the width of the rectangle used must be an even multiple°dONLNd
  6890. <!≥(=ZPof 16 bits. This limitation exists because the width of the rectangle is passed °dONLNd
  6891. R≥!˛(=—to SeedFill and°dONLNd
  6892. b!<-º(IZCalcMask as a number of °dONLNd
  6893. z!º-˛)Ä?words (2 bytes). When calculating this parameter, SeedCFill and°dONLNd
  6894. ∫-<9œ(UZLCalcCMask round down to an even word boundary. This rounding means that the °dONLNd -œ9˛(UÌ
  6895. rectangles°dONLNd 9<EÍ(aZYyou pass to CalcCMask and SeedCFill should be an even multiple of 16 pixels in width. If °dONLNd j9ÍE˛(athey°dONLNd oE<Qf(mZ@are not, then the rightmost portion of the mask will be garbage.°dONLNd ∞]<iı*(To figure out the color of the pixel at °dONLNd ÿ]ıi˛)π3(seedH,seedV), SeedCFill calls GetCPixel. GetCPixel°dONLNd i<uΔ(ëZ finds the color of the pixel at °dONLNd ,iΔu˛)äB(h,v) in the current port. Therefore, if you pass a pixmap that is°dONLNd ou<Åa(ùZnot the °dONLNd wuaŞ)%Rpixmap of the current port you will get bizarre results. In other words, seedH and°dONLNd  Å<çfl(©Z\seedV are expressed in the local coordinates of the current port, not the coordinate of the °dONLNd
  6896. &Åflç˛(©˝source°dONLNd
  6897. -ç<ôc(µZpixmap. ◊X◊
  6898. *7Color QuickDraw Q&As(Ï˙19)
  6899.  of 31ˇ◊#ˇ ˇˇˇˇ#◊ 
  6900. IR,Times
  6901. .+6-Macintosh Technical Notes /4/˘
  6902. °dONLNd)H*    You have °dONLNd    H)⁄)0Qtwo methods to make it work. First, always pass the pixmap of the current port as°dONLNd[)5§(Q6Othe source parameter. If you are using an off-screen pixmap, it is a good idea °dONLNd™)§5⁄(Q¬
  6903. to have an°dONLNdµ5A*(]6<associated port for it, and then call SetPort, passing it a °dONLNdÒ5*A⁄(]H$pointer your off-screen port, before°dONLNdAMs(i6you call SeedCFill.°dONLNd*Yeú*FThe second method involves letting SeedCFill get some wrong value for °dONLNdpYúe⁄(Å∫ the color at°dONLNd}eq3(ç64(seedH,seedV) then using your own custom SearchProc °dONLNd±e3q⁄(çQ to do the real work. The default°dONLNd“q}(ô67SearchProc for SeedCFill relies on getting the correct °dONLNd    q}⁄)˛'color, but your SearchProc doesn’t have°dONLNd1}â%(•6to.°dONLNd5ï°K*
  6904. SeedCFill °dONLNd?ïK°⁄)3Nalso makes the assumption that the seedH and seedV parameters are in the local°dONLNdé°≠(…62coordinate system of the destination bitmap. This °dONLNd¿°≠⁄)Î)assumption comes into play when SeedCFill°dONLNdÍ≠π (’67calculates the seedH and seedV parameters for SeedFill.°dONLNd"≈—≥*UAll this means that SeedCFill only works correctly if the source pixmap, destination °dONLNdw≈≥—⁄(Ì—pixmap,°dONLNd—›x(˘6and current port all °dONLNdî—x›⁄)`Euse the same coordinate system. Because of the above problem, this is°dONLNd⁄›Èm(6Ialmost automatic since the current port’s portRect and the bounds of the °dONLNd#›mÈ⁄(ãsource pixmap have to°dONLNd9Èı{(6be the same anyway.°dONLNdM
  6905. ‘*&The easiest way to make all this work °dONLNds‘
  6906. ⁄)º3is to have your main port be an even multiple of 16°dONLNdß
  6907. ß(56Qpixels wide. Then, make sure that your source and destination structures (pixmap °dONLNd¯
  6908. ß⁄(5≈
  6909. or bitmap)°dONLNd%(A64are all the same size and all have origins of (0,0).
  6910. °dONLNd8=L*'#System 7.0ß1 BitMapToRgn limitation
  6911. °dONLNd\LX>* Written:°dONLNdeLdXÇ)L1/1/90°dONLNdlXd](Ä6Last reviewed:°dONLNd{Xddà)L12/7/90°dONLNdÉp|˝(ò6-BitMapToRegion does not work as described in °dONLNd∞p˝|⁄)Â*the Macintosh Tech Note “32-Bit QuickDraw:°dONLNd€|àG(§6:Version 1.2 Features” for a pixmap with baseAddr = (NuBus °dONLNd|Gà⁄(§eaddress). Which calls support°dONLNd3àî(∞61pixmap 32-bit base addressing with pmVersion = 4?°dONLNde†¨**___°dONLNdi∏ƒj*=As of System 7.0ß1, BitMapToRgn cannot handle a bitmap whose °dONLNd¶∏jƒ⁄(‡àbase address is in the°dONLNdΩƒ–!(Ï67NuBus address space or any bitmap that requires 32-bit °dONLNdÙƒ!–⁄(Ï?%addressing. The problem will be fixed°dONLNd–‹)(¯6for °dONLNd–)‹⁄)XSystem 7’s final release. BitMapToRgn seems to be the only call that doesn’t yet support°dONLNdw‹Ëí(632-bit addressed bitmaps.°dONLNdëÙ9*X-Ref:°dONLNdò y* EDTS Macintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features” ◊4◊˘
  6912. *ƒ20)
  6913.  of 31(ÏîColor QuickDraw Q&Asˇ¸◊#ˇ ˇˇˇˇ#◊ 
  6914. IR,Times
  6915. .+Z-Developer Support Center(-fi
  6916. December 1992 /X/
  6917. °dONLNd)<8v(TZ*Macintosh Color QuickDraw and packed PICTs
  6918. °dONLNd+8<Db* Written:°dONLNd48àD¶)L1/1/90°dONLNd;D<PÅ(lZLast reviewed:°dONLNdJDàP¨)L12/7/90°dONLNdR\<h(ÑZ(Does Macintosh 32-Bit QuickDraw support °dONLNdz\h˛)’-packed PICTs? What’s the technique for saving°dONLNd®h<tt(êZ<packed PICT formats? What compression schemes are supported?°dONLNdÂt<ÄN* ___°dONLNdÈå<òb*7Color QuickDraw has always supported packed PICTs. See °dONLNd åbòÉ(¥ÄInside °dONLNd'åÉò¥)!    Macintosh°dONLNd0å¥ò˛)1
  6919.  Volume V for°dONLNd>ò<§Â(¿ZOdetails on how CLUT pixmaps are packed. Under 32-Bit QuickDraw, to pack direct °dONLNdçò§˛(¿RGB°dONLNdë§<∞(ÃZ[pixmaps in PICTs, call CopyBits with the packType field in the source pixmap set to one of °dONLNdϧ∞˛(Ãthe°dONLNd∞<º=(ÿZ5following constants that apply to direct RGB pixmaps:°dONLNd&»<‘ä*E0—default packing (pixelSize 16 defaults to packType 3 and pixelSize °dONLNdk»ä‘˛(®32 defaults to packType°dONLNdÉ‘<‡F(¸Z4)°dONLNd܇<ÏÇ* 1—no packing°dONLNdìÏ<¯˙* &2—remove pad byte (32-bit pixels only)°dONLNd∫¯<n* ?3—run-length encoding by pixel size chunks (16-bit pixels only)°dONLNd˙<ë* G4—run-length encoding, all of one component at the time, one scan line °dONLNdAë˛(,Øat a time (24-bit pixels°dONLNdZ<U(8Zonly)°dONLNd`(<4w*DScheme 4 will store the alpha channel also if cmpCount is set to to °dONLNd§(w4˛(Pï. PackSize is not used and°dONLNd¿4<@a(\Zshould °dONLNd«4a@˛)%Pbe set to 0 for compatibility reasons. These are the only compression techniques°dONLNd@<L•(hZsupported at this time.
  6920. °dONLNd0d<sQ*'(Macintosh PICT color picture file format
  6921. °dONLNdYs<b* Written:°dONLNdbsà¶)L1/1/90°dONLNdi<ãÅ(ßZLast reviewed:°dONLNdxàã≤)L11/21/90°dONLNdÅó<£J(øZIs °dONLNdÑóJ£˛)Wthere a general file format for color pictures that is common to all of the color paint°dONLNd‹£<Ø(ÀZ(programs? If so, where is it documented?°dONLNdØ<ªN* ___°dONLNd    «<”Å*DApple supports (and encourages developers to support) one file type °dONLNdM«Å”˛(Ôüfor pictures: the PICT file°dONLNdi”<fl+(˚Z1type. Most paint-type programs handle PICT files.°dONLNdõÎ<˜í*KA PICT file is composed of two parts in its data fork; the first 512 bytes °dONLNdÊÎí˜˛(∞are for the file header,°dONLNdˇ˜<|(Z;which contains application-dependent information. You have °dONLNd:˜|˛(öto contact the individual°dONLNdT<\(+Z=publishers to find out their particular data structures. For °dONLNdë\˛(+zexample, you can contact Claris°dONLNd±<o(7Z
  6922. Technical °dONLNdªo˛)3FSupport at AppleLink CLARIS.TECH or (415) 962-0371 for the file header°dONLNd<'ø(CZMacDraw writes to its files.°dONLNd3<?È*SThe rest of the data in the file is picture data as created by Macintosh QuickDraw °dONLNdr3È?˛([with°dONLNdw?<Ke(gZ=OpenPicture. You can find the information about this data in °dONLNd¥?eK´(gÉ Volume V of °dONLNd¿?´K˛)FInside Macintosh°dONLNd—K<Wá(sZE(pages 84–105); this section also shows how to read/write PICT files.°dONLNdc<of*You can °dONLNdcfo˛)*Qalso check the Macintosh Tech Note “Displaying Large PICT Files” for more details°dONLNdqo<{Å(óZon the subject. ◊X◊
  6923. *UColor QuickDraw Q&As(Ï˙21)
  6924.  of 31ˇ
  6925. ö◊#ˇ ˇˇˇˇ#◊ 
  6926. IR,Times
  6927. .+6-Macintosh Technical Notes /4/˘
  6928. °dONLNd)5>*$X-Refs:°dONLNd5Au* FDTS Macintosh Technical Note “QuickDraw’s Internal Picture Definition”°dONLNdOAMA* :DTS Macintosh Technical Note “Displaying Large PICT Files”
  6929. °dONLNdäet∏*'<Mac pixmap is clipped to visRgn defined by screenBits.bounds
  6930. °dONLNd«tÄ>* Written:°dONLNd–tdÄÇ)L1/1/90°dONLNd◊Äå](®6Last reviewed:°dONLNdÊÄdåé)L11/21/90°dONLNdÔò§k(¿6I’m drawing into °dONLNdòk§⁄)SJa large off-screen bitmap (pixmap), but anything drawn outside the 640- by°dONLNdK§∞É(Ã6K480-pixel Macintosh screen area doesn’t get written to the pixmap. Why not?°dONLNdó∞º** ___°dONLNdõ»‘@*6When you create a new port with OpenPort or OpenCPort °dONLNd—»@‘⁄(^ the visRgn is initialized to the°dONLNdÚ‘‡9(¸6<rectangular region defined by screenBits.bounds (IM I:163). °dONLNd.‘9‡⁄(¸W"If your port has a large portRect,°dONLNdQ‡Ï(6*any drawing will be clipped to the visRgn °dONLNd{‡Ï⁄)ÿ,and you will lose any drawing outside of the°dONLNd®Ï¯°(6screenBits.bounds rectangle.°dONLNd≈ä*QTo correct this set the visRgn of the port to coincide with your port’s portRect °dONLNdä⁄(,®after creating the°dONLNd)/(86port.°dONLNd/(4*5Also note that OpenPort initializes the clipRgn to a °dONLNdd(4⁄(P8%wide-open rectangular region (-32768,°dONLNdä4@ˇ(\6--32768, 32767, 32767). Some operations, like °dONLNd∑4ˇ@⁄)Á-OpenPicture, can fail with this setup, so try°dONLNdÂ@L…(h6'setting clipRgn to a smaller rectangle.°dONLNd
  6931. Xd>*X-Refs:°dONLNddp4* 8DTS Macintosh Technical Note “Pictures and Clip Regions”°dONLNdNp|o* CDTS Macintosh Technical Note “Drawing into an Off-Screen Pixel Map”
  6932. °dONLNdíî£π*';Using Macintosh System 7 OpenCPicture for higher resolution
  6933. °dONLNdŒ£Ø>* Written:°dONLNd◊£dØÇ)L1/1/90°dONLNdfiت](◊6Last reviewed:°dONLNdÌØdªà)L12/7/90°dONLNdı«”O(Ô6AWe want to use OpenCPicture for higher resolution, not for color °dONLNd6«O”⁄(Ômper se. Can OpenCPicture in°dONLNdR”fl¨(˚6OSystem 7 be used with non-Color as well as Color QuickDraw Macintosh computers?°dONLNd¢flÎ** ___°dONLNd¶˜3*Yes, °dONLNd´˜3⁄)Owith System 7, OpenCPicture can be used to create extended PICT2 files from all°dONLNd˚”(+6"Macintosh computers. Under System °dONLNd”⁄)ª26.0.7 or later, you must test for 32-Bit QuickDraw
  6934. °dONLNdP(76&before using OpenCPicture. You can do  °dONLNdv⁄)¸ this by calling Gestalt with the°dONLNdó'(C60gestaltQuickdrawVersion selector. If it returns °dONLNd«'⁄)ˆ&gestalt32BitQD or greater, then 32-Bit°dONLNdÓ'3á(O6QuickDraw is installed. ◊4◊˘
  6935. *ù22)
  6936.  of 31(ÏîColor QuickDraw Q&AsˇZ◊#ˇ ˇˇˇˇ#◊ 
  6937. IR,Times
  6938. .+Z-Developer Support Center(-fi
  6939. December 1992 /X/
  6940. °dONLNd)<8Y(TZ(How to identify 32-Bit QuickDraw version
  6941. °dONLNd)8<Db* Written:°dONLNd28àD¶)L1/1/90°dONLNd9D<PÅ(lZLast reviewed:°dONLNdHDàP≤)L11/21/90°dONLNdQ\<hÂ(ÑZSHow can my program find out which version of Macintosh 32-Bit QuickDraw is running?°dONLNd•h<tN* ___°dONLNd©Ä<åÇ*The following °dONLNd∑ÄÇå˛)FKcode snippet demonstrates how to use the Gestalt Manager to determine which°dONLNdå<òb(¥Zversion °dONLNd åbò˛)&Tof 32-Bit QuickDraw is installed. There is no way to determine the version of 32-Bit°dONLNd`ò<§y(¿Z<QuickDraw before Gestalt. For 32-Bit QuickDraw version 1.2, °dONLNdúòy§·(¿óGestalt returns 2.2. °dONLNd±ò·§˛)hInside°dONLNd∏§<∞m(ÃZ    Macintosh°dONLNd¡§m∞`)13 Volume VI describes the Gestalt Manager in detail.,
  6942. Courier
  6943.     °dONLNdıº<«á(„Z#defineTRUE0xFF°dONLNdΔ<—}*
  6944.  
  6945. #defineFALSE0°dONLNd–<€π*
  6946. #define Gestalttest0xA1AD°dONLNd-⁄<†*
  6947. #define NoTrap0xA89F°dONLNdBÓ<˘Z*main()°dONLNdI¯<A*
  6948. {°dONLNdK<
  6949. i*
  6950.     OSErrerr;°dONLNdU <x*
  6951. longfeature;°dONLNdb <+r*>if ((GetTrapAddress(Gestalttest) != GetTrapAddress(NoTrap))) {°dONLNd°*<51*
  6952. 1err = Gestalt(gestaltQuickdrawVersion, &feature);°dONLNd”4<?s*
  6953. if (!err) {°dONLNdfl><I·*
  6954. !if ((feature & 0x0f00) == 0x0000)°dONLNdH<S©*
  6955. Iprintf ("We have Original QuickDraw version 0.%x\n", (feature & 0x00ff));°dONLNdKR<]˙*
  6956. &else if ((feature & 0x0f00) == 0x0100)°dONLNdr\<gö*
  6957. Fprintf ("We have 8 Bit QuickDraw version 1.%x\n", (feature & 0x00ff));°dONLNdπf<q˙*
  6958. &else if ((feature & 0x0f00) == 0x0200)°dONLNd‡p<{ü*
  6959. Gprintf ("We have 32 Bit QuickDraw version 2.%x\n", (feature & 0x00ff));°dONLNd(z<ÖP*
  6960. else°dONLNd-Ñ<è“*
  6961. printf ("We don't have QD\n");°dONLNdLé<ôA*
  6962. }°dONLNdNò<£P*
  6963. else°dONLNdS¢<≠Ê*
  6964. "printf ("Gestalt err = %i\n",err);°dONLNdv¨<∑A*
  6965. }°dONLNdx∂<¡P*
  6966. else°dONLNd}¿<À¥*
  6967. printf ("No Gestalt\n");°dONLNdñ <’A*
  6968. }
  6969. °dONLNdòÏ<˚ƒ*&6Macintosh QDError function under System 6 and System 7
  6970. °dONLNdœ˚<b* Written:°dONLNdÿ˚à¶)L1/1/90°dONLNdfl<Å(/ZLast reviewed:°dONLNdÓà¨)L12/7/90°dONLNdˆ<+Ï(GZUnder what System 7 and System °dONLNdÏ+˛)∞66 conditions is it legal to call the Macintosh QDError°dONLNdL+<7h(SZ    function?°dONLNdV7<CN* ___°dONLNdZO<[*&Under System 7, QDError can be called °dONLNdÄO[˛)Δ0from all Macintosh computers. (System 7 supports°dONLNd±[<gÕ(ÉZCRGBForeColor, RGBBackColor, GetForeColor, and GetBackColor for all °dONLNdÙ[Õg˛(ÉΠ   Macintosh°dONLNd˛g<sq(èZ
  6971. computers °dONLNdgqs˛)5Jas well.) On a non-Color QuickDraw Macintosh, QDError always returns a “no°dONLNdSs<Ó(õZ error.” Under System 6, QDError °dONLNdssÓ˛)≤0cannot be used for non-Color QuickDraw Macintosh°dONLNd§<ãf(ßZsystems. ◊X◊
  6972. *EColor QuickDraw Q&As(Ï˙23)
  6973.  of 31ˇ ◊#ˇ ˇˇˇˇ#◊ 
  6974. IR,Times
  6975. .+6-Macintosh Technical Notes /4/˘
  6976. °dONLNd,ò*Macintosh CopyBits transfer modes changed for System 7
  6977. °dONLNd7,8>* Written:°dONLNd@,d8Ç)L1/1/90°dONLNdG8D](`6Last reviewed:°dONLNdV8dDà)L12/7/90°dONLNd^P\
  6978. (x6.Why do some Macintosh CopyBits transfer modes °dONLNdåP
  6979. \⁄)Ú+produce different results for System 7 than°dONLNd∏\hZ(Ñ6
  6980. for System 6?°dONLNdΔht** ___°dONLNd Äåñ*LUnder System 6, the srcOr, srcXor, srcBic, notSrcCopy, notSrcOr, notSrcXor, °dONLNdÄñå⁄(®¥
  6981. and notSrcBic°dONLNd$åòØ(¥6Xtransfer modes do not produce the same effect for a 16- or 32-bit (direct) pixel map as °dONLNd|åØò÷(¥Õfor an 8°dONLNdÑå÷ò⁄)'-°dONLNdÖò§Œ(¿6Xbit or shallower (indexed) pixel map. With Color QuickDraw these classic transfer modes °dONLNd›òŒ§⁄(¿Ïon°dONLNd‡§∞R(Ã6Adirect pixel maps aren’t color-based; they’re pixel-value-based. °dONLNd!§R∞⁄(ÃpColor QuickDraw performs°dONLNd:∞ºº(ÿ6Zlogical operations corresponding to the transfer mode on the source and destination pixel °dONLNdî∞ºº⁄(ÿ⁄values°dONLNdõº»©(‰6!to get the resulting pixel value.°dONLNdΩ‘‡Ù*/For example, say that a multicolored source is °dONLNdϑه⁄)‹/being copied onto a black-and-white destination°dONLNd‡ÏË(6,using the srcOr transfer mode, and both the °dONLNdH‡ËÏ⁄)–3source and destination are 8 bits per pixel. Except°dONLNd|ϯV(6Din unusual cases, the pixel value for black on an indexed pixel map °dONLNd¿ÏV¯÷(thas all its bits set, so an 8°dONLNd›Ï÷¯⁄)Ä-°dONLNdfi¯¿( 6`bit black pixel has a pixel value of $FF. Similarly, the pixel value for white has all its bits °dONLNd>¯¿⁄( ficlear,°dONLNdE’(,6*so an 8-bit white pixel has a pixel value °dONLNdo’⁄)Ω5of $00. CopyBits takes each pixel value of the source°dONLNd•Ø(86and performs a logical OR with °dONLNdƒØ⁄)ó=the corresponding pixel value of the destination. Using OR to°dONLNd(X(D6Dcombine any value with 0 results in the original value, so using OR °dONLNdFX(⁄(Dvto combine any pixel value°dONLNda(4´(P6with the pixel value for white °dONLNdÄ(´4⁄)ì<results in the original pixel value. Using OR to combine any°dONLNdΩ4@í(\6Qvalue with 1 results in 1, so using OR to combine any pixel value with the pixel °dONLNd4í@⁄(\∞value for black°dONLNd@L≤(h6Vresults in the pixel value for black. The resulting image shows the original image in °dONLNdt@≤L⁄(h–    all areas°dONLNd~LXp(t6Cwhere the destination image was white and shows black in all areas °dONLNd¡LpX⁄(téwhere the destination°dONLNd◊Xdj(Ä6image was black.°dONLNdËp|~*HTake the same example, but this time make the source and destination 32 °dONLNd0p~|⁄(òúbits per pixel. The°dONLNdD|àú(§6direct-color pixel value for °dONLNda|úà⁄)Ñ@black is $00000000 and the direct-color pixel value for white is°dONLNd¢àî’(∞6%$00FFFFFF. CopyBits still performs a °dONLNd«à’î⁄)Ω6logical OR on the source and destination pixel values,°dONLNd˛î†(º62but notice what happens in this case. Using OR to °dONLNd0î†⁄)˘'combine any source pixel value with the°dONLNdX†¨ñ(»6Qpixel value for white results in white, and using OR to combine any source pixel °dONLNd©†ñ¨⁄(»¥value with the°dONLNd∏¨∏A(‘6Cpixel value for black results in the original color. The resulting °dONLNd˚¨A∏⁄(‘_image shows the original image°dONLNd    ∏ƒ%(‡6in °dONLNd    ∏%ƒ⁄)
  6982. Vall areas where the destination image was black and shows white in all areas where the°dONLNd    tƒ–“(Ï6Ydestination image was white—roughly the opposite of what you see on an indexed pixel map.°dONLNd    Œ‹Ë¡*LThe newer transfer modes addOver, addPin, subOver, subPin, adMax, and adMin °dONLNd
  6983. ‹¡Ë⁄(flwork°dONLNd
  6984. ËÙ`(6consistently at °dONLNd
  6985. /Ë`Ù⁄)HMall pixel depths, and often, though not always, correspond to the theoretical°dONLNd
  6986. }ÙN(6>effect of the old transfer modes. For example, the adMin mode °dONLNd
  6987. ªÙN⁄(lworks similarly to the srcOr°dONLNd
  6988. ÿ °((6Jmode on both direct and indexed pixel maps. Also, 1-bit deep source pixel °dONLNd "° ⁄((ø    maps work°dONLNd , ∏(46Xconsistently and predictably regardless of the pixel depth of the destination even with °dONLNd Ñ ∏⁄(4÷the old°dONLNd å$b(@6transfer modes.°dONLNd ú0<é*IUnder system software version 7.0, the old transfer modes now perform by °dONLNd Â0é<⁄(X¨calculating with°dONLNd ˆ<H9(d6colors °dONLNd ˝<9H⁄)!Trather than pixel values. You’ll find that transfer modes like srcOr and srcBic work°dONLNd RHT(p61much more consistently even on direct pixel maps. ◊4◊˘
  6989. *|24)
  6990.  of 31(ÏîColor QuickDraw Q&Asˇ6◊#ˇ ˇˇˇˇ#◊ 
  6991. IR,Times
  6992. .+Z-Developer Support Center(-fi
  6993. December 1992 /X/
  6994. °dONLNd)<8r(TZ+Which QuickDraw versions support SetEntries
  6995. °dONLNd,8<Db* Written:°dONLNd58àD¶)L3/3/92°dONLNd<D<PÅ(lZLast reviewed:°dONLNdKDàP¨)L6/30/92°dONLNdS\<hr(ÑZ I’m calling °dONLNd_\rh˛)6NSetEntries to update the on-screen CLUT. Who implements this call? Does 32-Bit°dONLNdÆh<tñ(êZBQuickDraw? In other words, does the 32-Bit QuickDraw INIT need to °dONLNdhñt˛(ê¥be around for this to°dONLNdt<Ä(úZ%work? What about monochrome machines?°dONLNd-å<ò€*UI’m creating off-screen buffers by hand instead of using GWorlds. Is this the proper °dONLNdÇå€ò˛(¥˘way of°dONLNdâò<§˘(¿Z[doing off-screen buffering when we don’t want to require the user to have 32-Bit QuickDraw?°dONLNd§<∞N* ___°dONLNdȺ<»j*?SetEntries is part of the Color Manager, which exists with all °dONLNd(ºj»˛(‰àColor QuickDraw versions. A°dONLNdD»<‘Z(Z<good rule of thumb to follow is that if it is documented in °dONLNdÄ»Z‘{(xInside °dONLNdá»{‘¨)!    Macintosh°dONLNd껨‘˛)1 Volume V, you°dONLNdü‘<‡˜(¸Z'don’t need 32-Bit QuickDraw to use it. °dONLNdΔ‘˜‡H)ªInside Macintosh°dONLNd÷‘H‡K)Q °dONLNd◊‘K‡˛)!Volume V documents standard Color°dONLNd˘‡<ÏX(Z2QuickDraw. SetEntries does not work on monochrome °dONLNd+‡XÏ˛(vMacintosh models, including the°dONLNdKÏ<¯€(ZClassic II, SE, and PowerBooks.°dONLNdk<•*Off-screen buffering: °dONLNdÅ•˛)iDYou should always use GWorlds if they exist; use Gestalt to test for°dONLNdΔ<È(8ZUthem. This will assure that you can take advantage of the latest speed improvements. °dONLNdÈ˛(8It is°dONLNd!<(ı(DZWimportant to remember that under System 7 NewGWorld and accompanying calls are present °dONLNdxı(˛(Din°dONLNd{(<4y(PZ?all Macintosh computers including black-and-white systems such °dONLNd∫(y4˛(Póas Classic and PowerBook°dONLNd”4<@{(\Z 100 systems.
  6996. °dONLNd‡X<g*'+Macintosh pixel map maximum rowBytes change
  6997. °dONLNd g<sb* Written:°dONLNdgàs¨)L4/22/91°dONLNds<Å(õZLast reviewed:°dONLNd,sà¨)L6/10/91°dONLNd4ã<óŸ(≥ZThe Color QuickDraw section of °dONLNdSãŸó+)ùInside Macintosh°dONLNdcã+ó˛)R- Volume VI states that the restriction on the°dONLNdëó<£Î(øZWrowBytes field in a pixmap has been relaxed from $2000 to $4000. When did this happen? °dONLNdËóΣ˛(ø    Is it°dONLNdÓ£<ؘ(ÀZ\true for all 32-Bit QuickDraw versions? This affects our user configuration recommendations.°dONLNdKØ<ªN* ___°dONLNdO«<”*(The maximum rowBytes extension to $3FFF °dONLNdw«”˛)ÿ/or less applies only to 32-bit QuickDraw. Using°dONLNdß”<fl(˚Z)pixmaps with rowBytes greater than $1FFF °dONLNd–”fl˛)“1when 32-bit QuickDraw is not present is likely to°dONLNdfl<Îà(Zcause problems °dONLNdflàβ)LHsuch as garbage images or system crashes. Remember that 32-bit QuickDraw°dONLNdZÎ<˜Ë(Z#is always present under System 7.0.
  6998. °dONLNd~<î*'3Use assembly to flip a 24-bit off-port color pixmap
  6999. °dONLNd≤<*b* Written:°dONLNdªà*¶)L5/7/91°dONLNd¬*<6Å(RZLast reviewed:°dONLNd—*à6¨)L7/25/91°dONLNdŸB<N¢(jZMWhat’s the best approach to horizontally flip a 24-bit off-port color pixmap?°dONLNd'N<ZN* ___°dONLNd+f<rÇ*BUnfortunately, you won’t be able to use CopyBits for this kind of °dONLNdmfÇr˛(é†procedure; you’ll have to°dONLNdár<~€(öZwrite your own routine to move °dONLNd¶r€~˛)ü:each pixel. I’d suggest doing this in assembly language to°dONLNd·~<äE(¶Z7squeeze the best possible performance out of your code. ◊X◊
  7000. *FColor QuickDraw Q&As(Ï˙25)
  7001.  of 31ˇæ◊#ˇ ˇˇˇˇ#◊ 
  7002. IR,Times
  7003. .+6-Macintosh Technical Notes /4/˘
  7004. °dONLNd,í*:Construct a 'clut' instead of changing b/w palette entries
  7005. °dONLNd;,8>* Written:°dONLNdD,d8à)L6/10/91°dONLNdL8D](`6Last reviewed:°dONLNd[8dDÇ)L8/1/91°dONLNdbP\°(x6UHow can I change the first and last (white and black) entries in a Macintosh palette?°dONLNd∏\h** ___°dONLNdºtÄΔ*YThe answer to your question about changing the black and white entries in a palette is a °dONLNdtΔÄ⁄(ú‰little°dONLNdÄåÀ(®6Zstrange. You can’t simply change the palette associated with an on-screen window, because °dONLNdvÄÀå⁄(®Ètoo°dONLNdzåòŸ(¥6amany portions of the Toolbox/OS assume that the first entry is white and the last entry is black.°dONLNd‹§∞z*However, what you °dONLNdÓ§z∞ä)bcan°dONLNdÒ§ä∞ƒ)F do is create an off-screen GWorld and construct a 'clut' for it that °dONLNd7§ƒ∞⁄(Âdoes°dONLNd<∞º0(ÿ6=what you want. Creating the 'clut' is fairly straightforward:,
  7006. Courier
  7007.     °dONLNdz»”˛*./* Making a reversed gray-scale color table */°dONLNd©‹ÁÅ*CTabHandle offColors;°dONLNdø˚l*DoffColors = (CTabHandle) NewHandleClear (sizeof (ColorTable) + 255 *°dONLNd˙¬*
  7008. "              sizeof (ColorSpec));°dONLNd'ü*
  7009. (**offColors).ctSize = 255;°dONLNdC+*
  7010. 7for (index = 0; index <= (**offColors).ctSize; index++)°dONLNd{#'*
  7011.   {°dONLNd"-*
  7012. 0    (**offColors).ctTable [index].value = index;°dONLNd∞,7]*
  7013. A    (**offColors).ctTable [index].rgb.red = (index << 8) | index;°dONLNdÚ6Ag*
  7014. C    (**offColors).ctTable [index].rgb.green = (index << 8) | index;°dONLNd6@Kb*
  7015. B    (**offColors).ctTable [index].rgb.blue = (index << 8) | index;°dONLNdyJU'*
  7016.   }°dONLNd}T_ö*
  7017. (**offColors).ctFlags = 0;°dONLNdò^iÃ*
  7018. $(**offColors).ctSeed = GetCTSeed ();
  7019. °dONLNdΩtÄh*ENote that using this 'clut' with an off-screen GWorld will work fine °dONLNdthÄä(úÜexcept °dONLNd    täÄ—)"if you attempt °dONLNdt—Ä⁄)Gto°dONLNdÄåo(®6Fdraw text into the GWorld. Apparently drawing text off screen carries °dONLNdaÄoå⁄(®çthe same assumptions°dONLNdvåòÆ(¥6 that all drawing does on screen.°dONLNdó§∞œ*XOnce you have done your off-screen drawing with the reversed 'clut' as described above, °dONLNdÔ§œ∞⁄(ÃÌall°dONLNdÛ∞º (ÿ6Wthat remains is to CopyBits from your off-screen GWorld to your on-screen window. Your °dONLNdJ∞ º÷(ÿËon°dONLNdL∞÷º⁄) -°dONLNdMº»<(‰6>screen window will need the appropriate palette. Fortunately, °dONLNdãº<»⁄(‰Z"constructing that palette from the°dONLNdÆ»‘](6'clut' is trivial:
  7020.     °dONLNd¡‡ÎÆ*/* Make a palette out of it */°dONLNd‡Íıè*
  7021. KaPalette = NewPalette (offColors, (**offColors).ctSize + 1, pmTolerant, 0);
  7022. °dONLNd, Á**Attaching this palette to the window will °dONLNdVÁ ⁄)œ-cause the correct remapping to occur when you°dONLNdÑ ñ(46MCopyBits from the GWorld to the window, and everything should look just fine. ◊4◊˘
  7023. *∏26)
  7024.  of 31(ÏîColor QuickDraw Q&AsˇÚ◊#ˇ ˇˇˇˇ#◊ 
  7025. IR,Times
  7026. .+Z-Developer Support Center(-fi
  7027. December 1992 /X/
  7028. °dONLNd)<8Δ(TZ7Why PlotCIcon requires GetCIcon instead of Get1Resource
  7029. °dONLNd88<Db* Written:°dONLNdA8àD¨)L4/26/91°dONLNdID<PÅ(lZLast reviewed:°dONLNdXDàP¨)L6/17/91°dONLNd`\<h§(ÑZWhy do I have to use °dONLNdu\§h˛)hEGetCIcon(resID) instead of Get1Resource('cicn',resID) forPlotCIcon to°dONLNdªh<tÜ(êZwork correctly?°dONLNdÀt<ÄN* ___°dONLNdœå<òS*You °dONLNd”åSò˛)[apparently thought something that, at first, I thought also: that GetCIcon(resID) is just a°dONLNd/ò<§ô(¿ZHutility routine that translates to Get1Resource('cicn',resID). However, °dONLNdwòô§˛(¿∑this is not the case;°dONLNdç§<∞/(ÃZ3GetCIcon not only gets the 'cicn' resource, but it °dONLNd¿§/∞˛)Û'also performs some minor surgery on the°dONLNdË∞<ºı(ÿZ*results, fills in some placeholder fields °dONLNd∞ıº˛)π8in the resource data, and the like. Basically, PlotCIcon°dONLNdKº<»)(‰Z1can’t work without the things that GetCIcon does.
  7030. °dONLNd}‡<Ô⁄*';CopyBits maps source pixmap colors to GDevice inverse table
  7031. °dONLNdπÔ<˚b* Written:°dONLNd¬Ôà˚¶)L4/3/91°dONLNd…˚<Å(#ZLast reviewed:°dONLNdÿ˚à¨)L6/17/91°dONLNd‡<‰(;ZWI’m trying to draw off screen so I made my own CGrafPort, pixmap, and color table, but °dONLNd7‰˛(;when°dONLNd<<+~(GZDI draw into it, the colors come out all wrong. What’s going on here?°dONLNdÅ+<7N* ___°dONLNdÖC<O£*It’s a very common °dONLNdòC£O˛)gCmisconception that CopyBits maps the colors available in the source°dONLNd‹O<[ø(wZUpixmap’s color table to the colors available in the destination pixmap’s color table.°dONLNd2g<s∏*What actually happens is °dONLNdKg∏s˛)|@that CopyBits maps the colors in the source pixmap to the colors°dONLNdås<<(õZ6available in the current GDevice’s inverse table. See °dONLNd¬s<é(õZInside Macintosh°dONLNd“séª)R Volume °dONLNd⁄sª˛)- V, pages 137°dONLNdÁ<ãa(ßZ@through 139 for a description of inverse tables. Inverse tables °dONLNd'aã˛(ß is a backwards color table. With°dONLNdHã<ó(≥Z1a color table, you use a pixel value as an index °dONLNdyãó˛)fi1into the table to return a color. With an inverse°dONLNd´ó<£6(øZ3table, you use a color-like value as an index into °dONLNdfió6£˛)˙'the table to return a pixel value. When°dONLNd£<Øò(ÀZFCopyBits maps colors from one pixel map to another, it takes a source °dONLNdL£òØ˛(À∂pixel value, uses the°dONLNdbØ<ªï(◊ZJsource pixmap’s color table to get the corresponding color, and uses that °dONLNd¨Øïª˛(◊≥color as an index into°dONLNd√ª<«(„Z'the current GDevice’s inverse table to °dONLNdͪ«˛)¥;get the pixel value of the closest color in the destination°dONLNd&«<”†(ÔZpixmap’s color table.°dONLNd<fl<Î)*2Generally speaking, every conceivable color table °dONLNdnfl)β)Ì-has exactly one conceivable inverse table. If°dONLNdúÎ<˜∞(Zyou alter the contents of °dONLNd∂Î∞˜˛)tIa color table, then the inverse table must likewise be altered. It’s just°dONLNd˜<∂(ZOlike numbers: for any number you give me, I can give you its negative. For any °dONLNdO˜∂˛(‘color table you°dONLNd_<Ó(+Z!give me, MakeITable can give you °dONLNdÄÓ·)≤/its inverse table. MakeITable is documented in °dONLNdØ·˛)ÛInside°dONLNd∂<m(7Z    Macintosh°dONLNdøm÷)1 Volume V, page 142.°dONLNd‘'<3j(OZ    Think of °dONLNd›'j3˛).Othe current GDevice as an implied parameter to CopyBits. If you don’t deal with°dONLNd    -3<?≤([ZNGDevices at all, then the current GDevice is always the main screen’s GDevice °dONLNd    {3≤?˛([–as far as you’re°dONLNd    å?<Kë(gZconcerned. Color °dONLNd    ù?ëK˛)UHQuickDraw often switches between different screens’ GDevices so that you°dONLNd    ÊK<W€(sZ"can draw to multiple screens, but °dONLNd
  7032. K€W˛)ü<that’s all handled behind your back. If you create a pixmap,°dONLNd
  7033. EW<c;(Z9give it a color table, and CopyBits to it, then the main °dONLNd
  7034. ~W;c˛)ˇ(screen’s GDevice’s inverse table is used°dONLNd
  7035. ßc<oô(ãZto map colors from °dONLNd
  7036. ∫côo˛)]Gthe source pixmap. That’s OK as long as your destination pixmap’s color°dONLNd o<{U(óZtable °dONLNd oU{˛)Xis compatible with the main screen’s inverse table. If you change the depth and/or color°dONLNd a{<á≤(£Ztable of the main screen, °dONLNd {{≤á˛)vCand then still CopyBits to this same pixmap with the same old depth°dONLNd øá<ìN(ØZ:and color table, then things won’t work correctly because °dONLNd ˘áNì˛(Øl#the main screen’s GDevice’s inverse°dONLNd ì<üæ(ªZRtable changes, making it incompatible with your destination pixmap’s color table. °dONLNd oìæü˛(ª‹ This problem°dONLNd |ü<´Ü(«ZKusually manifests itself as incorrect colors, but it can result in crashes. ◊X◊
  7037. *%Color QuickDraw Q&As(Ï˙27)
  7038.  of 31ˇú◊#ˇ ˇˇˇˇ#◊ 
  7039. IR,Times
  7040. .+6-Macintosh Technical Notes /4/˘
  7041. °dONLNd)5s*$To fix this, you’ll °dONLNd)s5⁄)[Ehave to remove your reliance on the main screen’s GDevice. To do that°dONLNdZ5A7(]6you’ll °dONLNda57A⁄)Qhave to make your own GDevice. There’s a routine called NewGDevice, but it always°dONLNd≥AMÇ(i6makes the GDevice in °dONLNd»AÇM⁄)jFthe system heap. Instead, you should just call NewHandle to allocate a°dONLNdMY9(u6<GDevice record yourself. Here’s what the fields should hold:°dONLNdLeq'*5gdRefNum—The GDevice has no driver, so set this to 0.°dONLNdÇ}â[*EgdID—It doesn’t matter what this is set to—might as well set it to 0.°dONLNd»ï°Ã*\gdType—Set this to 2 if the off-screen uses direct colors (16 or 32 bits per pixel) or 0 if °dONLNd$ïð⁄(ΩÍthe°dONLNd(°≠"(…6;off-screen uses a color table (1 through 8 bits per pixel).°dONLNddπ≈È*(gdITable—Allocate a small (maybe just a °dONLNdåπÈ≈⁄)—02-byte) handle for this field. After you’re done°dONLNdΩ≈—∂(Ì6!setting up this GDevice and your °dONLNdfi≈∂—⁄)û<off-screen pixmap, color table (if any), and CGrafPort, then°dONLNd—›F(˘6?set this GDevice as the current GDevice by calling SetGDevice. °dONLNdZ—F›⁄(˘dThen call MakeITable, passing°dONLNdx›Èƒ(6^it NIL for both the color table and inverse table parameters, and 0 for the preferred inverse °dONLNd÷›ƒÈ⁄(‚table°dONLNd‹ÈıK(6 resolution.°dONLNdË
  7042. i*gdResPref—I’d °dONLNdˆi
  7043. ⁄)QHguess that more than 99.9 percent of all inverse tables out there have a°dONLNd?
  7044. •(56Qresolution of 4. Unless you have some reason not to, I’d recommend the same here.°dONLNdë%1Ü*GgdSearchProc—Set to NIL. Use AddSearch if you want to use a SearchProc.°dONLNdŸ=I}*AgdCompProc—Set to NIL. Use AddComp if you want to use a CompProc.°dONLNdUaŸ*)gdFlags—Set to 0 initially, and then use °dONLNdDUŸa⁄)¡7SetDeviceAttribute after you’ve set up the rest of this°dONLNd|amE(â6GDevice.°dONLNdÖyÖ5*9gdPMap—Set this to be a handle to your off-screen pixmap.°dONLNdøëùÂ*'gdRefCon—Set this to whatever you want.°dONLNdÁ©µö*gdNextGD—Set this to nil.°dONLNd¡ÕO*?gdRect—Set this to be equal to your off-screen pixmap’s bounds.°dONLNdAŸÂÉ*IgdMode—Set this to -1. This is intended for GDevices with drivers anyway.°dONLNdãÒ˝É*gdCCBytes—Set to 0.°dONLNdü    Ç*gdCCDepth - Set to 0.°dONLNdµ!-Ñ*gdCCXData - Set to 0.°dONLNdÀ9Eâ*gdCCXMask - Set to 0.°dONLNd·Q]Ç*gdReserved - Set to 0.°dONLNd¯iu§*For gdFlags, you should use °dONLNdi§u⁄)å@SetDeviceAttribute to set the noDriver bit and the gDevType bit.°dONLNdUuŪ(ù6VYou should set the gDevType bit to 1 even if you have a monochrome color table. The 0 °dONLNd´uªÅ⁄(ùŸsetting°dONLNd≥Åçà(©6was only used when °dONLNdΔÅàç⁄)p;monochrome mode was handled by the video driver, and 32-Bit°dONLNdçô©(µ6PQuickDraw eliminated that convention. Your GDevice doesn’t have a driver anyway. ◊4◊˘
  7045. *728)
  7046.  of 31(ÏîColor QuickDraw Q&Asˇê◊#ˇ ˇˇˇˇ#◊ 
  7047. IR,Times
  7048. .+Z-Developer Support Center(-fi
  7049. December 1992 /X/
  7050. °dONLNd<)◊(EZOnce this is done, the GDevice °dONLNd◊)˛)õ;and the off-screen pixmap should be treated as inseparable.°dONLNd[)<5≠(QZWhen you CopyBits or °dONLNdp)≠5˛)qFdraws into the pixmap, first call SetGDevice to set its GDevice as the°dONLNd∑5<AØ(]ZKcurrent GDevice. When that’s done, call SetGDevice to restore the previous °dONLNd5ØA˛(]ÕGDevice. Doing°dONLNdA<M?(iZ6this insulates you from changes in a screen’s GDevice.°dONLNdHY<e*,If you alter your pixmap’s color table, you °dONLNdtYe˛)‘.should make sure you update the ctSeed of that°dONLNd£e<qX(çZcolor °dONLNd©eXq˛)Stable, either by assigning to it the result of GetCTSeed (documented on page 143 of°dONLNd˝q<}é(ôZInside Macintosh°dONLNd
  7051. qé}ü)R8 Volume V) or by passing a handle to the color table to °dONLNdEqü}˛(ôΩCTabChanged. The°dONLNdV}<âÅ(•Znext time that °dONLNde}Åâ˛)EHpixmap is drawn into, Color QuickDraw will update your GDevice’s inverse°dONLNdÆâ<ïy(±ZGtable automatically when it realizes that the ctSeed is different from °dONLNdıâyï˛(±óthe current GDevice (which°dONLNdï<°(ΩZ.had better be yours) inverse table’s iTabSeed.°dONLNd?≠<π*)GWorlds work this way on Color QuickDraw °dONLNdh≠π˛)‹*machines. Every GWorld comes with a pixmap°dONLNdìπ<≈Ù(·ZRand a GDevice. When you call SetGWorld, that sets both the GWorld and its GDevice °dONLNdÂπÙ≈˛(·as°dONLNdË≈<—a(ÌZcurrent.
  7052. °dONLNdÒÈ<¯u*',How Macintosh system draws small color icons
  7053. °dONLNd¯<b* Written:°dONLNd'¯à¨)L3/31/92°dONLNd/<Å(,ZLast reviewed:°dONLNd>à¨)L5/21/92°dONLNdF<(“(DZTThe code I added to my application’s MDEF to plot small icons in color works except °dONLNdö“(˛(Dfor when°dONLNd£(<4Ô(PZXI hold the mouse over an item with color. The color of the small icons is wrong because °dONLNd˚(Ô4˛(P
  7054. it’s°dONLNd4<@⁄(\Z!just doing an InvertRect. When I °dONLNd!4⁄@˛)û:drag over the Apple menu, the menu inverts behind the icon°dONLNd\@<L‡(hZ#but the icon is untouched. Is this °dONLNd@‡L˛)§9done by brute force, redrawing the small icon after every°dONLNdπL<Xr(tZ InvertRect?°dONLNd≈X<dN* ___°dONLNd…p<|í*DAs you figured out, the Macintosh system draws color icons, such as °dONLNd
  7055. pí|˛(ò∞the Apple icon on the°dONLNd#|<à(§Z2menu bar, every time the title has to be inverted.°dONLNdVî<†¬*The actual sequence of calls °dONLNds˛)ÜEis (more or less) as follows: first InvertRect is called to black the°dONLNdπ†<¨Y(»Zmenu °dONLNdæ†Y¨˛)Ytitle and then PlotIconID is called to draw the icon in its place. The advantage of using°dONLNd¨<∏Œ(‘ZVPlotIconID is that you don’t have to worry about the depth and size of the icon being °dONLNdn¨Œ∏˛(‘Ï    used. The°dONLNdx∏<ƒ.(‡Z,system picks the best match from the family °dONLNd§∏.ƒ˛)Ú%whose ID is being passed, taking into°dONLNd ƒ<–(ÏZconsideration °dONLNdÿƒ–˛)CPthe target rectangle and the depth of the device(s) that will contain the icon’s°dONLNd)–<‹\(¯Zimage.°dONLNd0Ë<ÙH*8The Icon Utilities call PlotIconID is documented in the °dONLNdhËHÙ˛(f"Macintosh Technical Note, “Drawing°dONLNdãÙ<‚(ZZIcons the System 7 Way.” Just in case you don’t have your stack at hand, the interface is:,
  7056. Courier
  7057.     °dONLNdÊ <˙*&    IconAlignmentType    =    INTEGER;°dONLNd    
  7058. <!˙*
  7059. &    IconTransformType    =    INTEGER;°dONLNd    4*<5˙*&    FUNCTION PlotIconID(theRect: Rect;°dONLNd    [4<?1*
  7060. 1                        align: IconAlignmentType;°dONLNd    ç><IE*
  7061. 5                        transform: IconTransformType;°dONLNd    √H<S6*
  7062. 2                        theResID: INTEGER): OSErr;°dONLNd    ˆR<]˙*
  7063. &        INLINE    $303C, $0500, $ABC9;°dONLNd
  7064. "f<qÎ*#typedef short    IconAlignmentType;°dONLNd
  7065. Fp<{Î*
  7066. #typedef short    IconTransformType;°dONLNd
  7067. jÑ<è*,pascal OSErr PlotIconID(const Rect *theRect,°dONLNd
  7068. óé<ô@*
  7069. 4                            IconAlignmentType align,°dONLNd
  7070. Ãò<£T*
  7071. 8                            IconTransformType transform,°dONLNd ¢<≠*
  7072. +                            short theResID) ◊X◊
  7073. *#Color QuickDraw Q&As(Ï˙29)
  7074.  of 31ˇP◊#ˇ ˇˇˇˇ#◊ 
  7075. IR,Times
  7076. .+6-Macintosh Technical Notes /4/˘,
  7077. Courier
  7078.     °dONLNd(≥*    = {0x303C, 0x0500, 0xABC9};
  7079. °dONLNd 3?ô*SPlease refer to the Tech Note referenced above for more details on using the calls.
  7080. °dONLNdtWf∞*'8Spooling and preserving Macintosh QuickDraw pixmap depth
  7081. °dONLNd≠fr>* Written:°dONLNd∂fdrà)L2/11/92°dONLNdær~](ö6Last reviewed:°dONLNdÕrd~à)L9/15/92°dONLNd’äñ†(≤6PWhen a picture that contains a pixmap is spooled into a window, how and when is °dONLNd%ä†ñ⁄(≤æ the depth of°dONLNd2ñ¢ï(æ6Qthe pixmap in the picture converted to the depth of the screens the window is on?°dONLNdÑ¢Æ** ___°dONLNdà∫ΔΩ*!When a picture is spooled in, if °dONLNd©∫ΩΔ⁄)•6QuickDraw encounters any bitmap opcode, it allocates a°dONLNd‡Δ“˚(Ó60pixmap of the same depth as the data associated °dONLNdΔ˚“⁄)„-with the bitmap opcode, expands the data into°dONLNd>“fi*(˙6the °dONLNdB“*fi⁄)Vtemporary pixmap, and then calls StdBits. StdBits is what triggers the depth and color°dONLNdôfiÍØ(6conversions as demanded by °dONLNd¥fiØÍ⁄)ó:the color environment (depth, color table, black-and-white°dONLNdÔ͈D(6
  7082. settings) °dONLNd˘ÍDˆ⁄),Mof the devices the target port may span (as when a window crosses two or more°dONLNdGˆC(6    screens).°dONLNdQÜ*If there’s not enough °dONLNdgÜ⁄)n?memory in the application heap or in the temporary memory pool,°dONLNdß&Å(B6QuickDraw bands the °dONLNdªÅ&⁄)iFimage down to one scan line and calls StdBits for each of these bands.°dONLNd&2ƒ(N6[Note that if you’re providing your own bitsProc, QuickDraw will call it instead of StdBits.°dONLNd^>JM*AThis process is the same when the picture is in memory, with the °dONLNdü>MJ⁄(fkobvious exception that all the°dONLNdæJVÇ(r6Npicture data is present; the color mapping occurs when StdBits does its stuff.
  7083. °dONLNd
  7084. n}*'$Determining the resolution of a PICT
  7085. °dONLNd2}â>* Written:°dONLNd;}dâà)L6/10/92°dONLNdCâï](±6Last reviewed:°dONLNdRâdïà)L9/15/92°dONLNdZ°≠[(…6EIn a version 2 picture, the picFrame is the rectangular bounding box °dONLNdü°[≠⁄(…yof the picture, at 72 dpi. I°dONLNdº≠πõ(’6would like to determine the °dONLNdÿ≠õπ⁄)ÉEbounding rectangle at the stored resolution or the resolution itself.°dONLNdπ≈ó(·6SIs there a way to do this without reading the raw data of the PICT resource itself?°dONLNdr≈—** ___°dONLNdv›ÈÃ*%With regular version 2 PICTs (or any °dONLNdõ›ÃÈ⁄)¥:pictures), figuring out the real resolution of the PICT is°dONLNd÷Èı©(6pretty tough. Applications use °dONLNdıÈ©ı⁄)ë?different techniques to save the information. But if you make a°dONLNd5ı≠(6picture with OpenCPicture, the °dONLNdTı≠⁄)ï>resolution information is stored in the headerOp data, and you°dONLNdì
  7086. ()65can get at this by searching for the headerOp opcode °dONLNd»
  7087. ⁄)˘+in the picture data (it’s always the second°dONLNdÙ
  7088. (569opcode in the picture data, but you still have to search °dONLNd-
  7089. ⁄(56)for it in case there are any zero opcodes°dONLNdW%ò(A6Ubefore it). Or you can use the Picture Utilities Package to extract this information.°dONLNd≠1=*8With older picture formats, the resolution and original °dONLNdÂ1=⁄(Y7&bounds information is sometimes not as°dONLNd     =Io(e6obvious or easily °dONLNd    =oI⁄)WJderived. In fact, in some applications, the PICT’s resolution and original°dONLNd    iIU (q66bounds aren’t stored in the header, but rather in the °dONLNd    üI U⁄)Ù+pixel map structure(s) contained within the°dONLNd    ÀUa6(}6PICT.°dONLNd    —myÄ*JTo examine these pixmaps, you’ll first need to install your own bitsProc, °dONLNd
  7090. mÄy⁄(ïûand then manually°dONLNd
  7091. -yÖ˝(°6/check the bounds, hRes, and vRes fields of any °dONLNd
  7092. \y˝Ö⁄)Â+pixmap being passed. In most cases the hRes°dONLNd
  7093. àÖë¡(≠6Mand vRes fields will be set to the Fixed value 0x00480000 (72 dpi); however, °dONLNd
  7094. ’Ö¡ë⁄(≠flsome°dONLNd
  7095. ⁄ëùŒ(π6_applications will set these fields to the PICT’s actual resolution, as shown in the code below. ◊4◊˘
  7096. *330)
  7097.  of 31(ÏîColor QuickDraw Q&AsˇX◊#ˇ ˇˇˇˇ#◊ 
  7098. IR,Times
  7099. .+Z-Developer Support Center(-fi
  7100. December 1992 /X/,
  7101. Courier
  7102.     °dONLNd<(»(DZRect            gPictBounds;°dONLNd'<2˙*
  7103. &Fixed            gPictHRes, gPictVRes;°dONLNdD;<Fc*;pascal void ColorBitsProc (srcBits, srcRect, dstRect, mode,°dONLNdÅE<Px*
  7104.     maskRgn)°dONLNdéO<ZØ*
  7105. BitMap        *srcBits;°dONLNd¶Y<dÎ*
  7106. #Rect            *srcRect, *dstRect;°dONLNd c<n™*
  7107. short            mode;°dONLNd·m<x•*
  7108. RgnHandle    maskRgn;°dONLNd˜w<ÇA*
  7109. {°dONLNd˘Å<å†*
  7110.     PixMapPtr    pm;°dONLNdã<ñ»*
  7111.     pm = (PixMapPtr)srcBits;°dONLNd+ï<†◊*
  7112.     gPictBounds = (*pm).bounds;°dONLNdKü<™@*
  7113. 4    gPictHRes = (*pm).hRes;        /* Fixed value */°dONLNdÄ©<¥@*
  7114. 4    gPictVRes = (*pm).vRes;        /* Fixed value */°dONLNdµ≥<æA*
  7115. }°dONLNd∑Ω<»æ*
  7116. void FindPictInfo(picture)°dONLNd“«<“ñ*
  7117. PicHandle picture;°dONLNd—<‹A*
  7118. {°dONLNdÁ€<Ê‹*
  7119.      CQDProcs        bottlenecks;°dONLNdÂ<‹*
  7120.      SetStdCProcs (&bottlenecks);°dONLNd)Ô<˙"*
  7121. .    bottlenecks.bitsProc = (Ptr)ColorBitsProc;°dONLNdX˘<T*
  7122. 8    (*(qd.thePort)).grafProcs = (QDProcs *)&bottlenecks;°dONLNdë<;*
  7123. 3    DrawPicture (picture, &((**picture).picFrame));°dONLNd≈
  7124. <Î*
  7125. #    (*(qd.thePort)).grafProcs = 0L;°dONLNdÈ<"A*
  7126. } ◊X◊
  7127. (ÏZColor QuickDraw Q&As(Ï˙31)
  7128.  of 31ˇ>◊#ˇ ˇˇˇˇ#◊†Ç 
  7129. /ZÅ#
  7130.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7131. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7132. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7133. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7134. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7135.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7136. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  7137. IR.°dONLNdz<ç,(ßZAdding Color With CopyBits
  7138. °dONLNdå<õr*Imaging°dONLNd#årõ˛(∑êM.IM.ColorCopyBits
  7139. °dONLNd6ß<≥q(œZ
  7140. Revised by°dONLNdBß≈≥˛(œ„
  7141. March 1988°dONLNdM≥<øq(€Z Written by:°dONLNdY≥Ñø≈)H
  7142. Chris Derossi°dONLNdg≥±ø˛(€œ
  7143. November 1987°dONLNduÀ<◊¿(ÛZInside Macintosh Volume V°dONLNdéÀ¿◊Q)Ñ  states that the foreground and °dONLNdÆÀQ◊˛)ë#background colors are applied to an°dONLNd“ÿ<‰Ö(Zimage during a ,
  7144. Courier°dONLNd·◊Ö„Ω)ICopyBits°dONLNdÈÿΩ‰Õ)8 or °dONLNdÌ◊Õ„)CopyMask°dONLNdıÿ‰á)8 call. Accidental use of this °dONLNdÿቲ)Çfeature can create bizarre°dONLNd.‰<ˆ( Z\coloring effects. This note explains what happens, how to avoid problems, and how to use it. X
  7145. °dONLNdã<$ô*4 What Happens
  7146. °dONLNdò0<<Æ*Color QuickDraw has a °dONLNdÆ0Æ<˛)rDfeature that will allow you to convert a monochrome image to a color°dONLNdÛ=<Iã(eZimage. During a °dONLNd<ãH√)OCopyBits°dONLNd =√IΔ)8 °dONLNd =ΔI‘)or °dONLNd<‘H )CopyMask°dONLNd= I˛)82 call, if the foreground and background colors are°dONLNdJI<U‘(qZTnot black and white, respectively, Color QuickDraw performs the following operation °dONLNdûI‘U˛(qÚon every°dONLNdßU<aï(}Zpixel being copied:
  7147.     °dONLNdºn`y+$%NOTE: color table index = pixel value°dONLNd„Ç`ç*%s = color table index of source pixel°dONLNd
  7148. å`ó2*
  7149. *fg = color table index of foreground color°dONLNd6ñ`°2*
  7150. *bg = color table index of background color°dONLNdb™`µU*1ColoredPixelValue = (NOT(s) AND bg) OR (s AND fg)
  7151. °dONLNdî¿<Ã0(ËZ3If your source image contains only black and white °dONLNd«¿0Ã˛)Ù*pixels, then all black pixels would become°dONLNdÚÃ<ÿF(ÙZ7the foreground color and all white pixels would become °dONLNd)ÃFÿ˛(Ùd%the background color. This is because°dONLNdOÿ<‰◊(Z]the color table index for white is all zeros and the color table index for black is all ones.°dONLNd≠Ò<˝m*>For example, suppose your source image was a 4-bit deep color °dONLNdÎm¸ó(ãPixMap°dONLNdÒÒó˝û)*. °dONLNdÛÒû˝˛)Then the color table°dONLNd˝<    ”(%ZWindex for white (in binary) is 0000 and the index for black is 1111. And let’s suppose °dONLNd_˝”    ˛(%Ò    that your°dONLNdi    <Û(1ZXforeground color is green with an index of 1101 while your background color is red with °dONLNd¡    Û˛(1an°dONLNdƒ<!ë(=ZGindex of 0011. Then for the black pixels, the above procedure produces:
  7152.     °dONLNd
  7153. -`8á+$;ColoredPixelValue = (NOT(1111) AND 0011) OR (1111 AND 1101)°dONLNdJ7`Bá*
  7154. ;     1101         = (  0000    AND 0011) OR (1111 AND 1101)
  7155. °dONLNdÜM<Y(uZ-And the operation on the white pixels yields:
  7156.     °dONLNdµf`qá+$;ColoredPixelValue = (NOT(0000) AND 0011) OR (0000 AND 1101)°dONLNdÚp`{á*
  7157. ;     0011         = (  1111    AND 0011) OR (0000 AND 1101) ◊X◊
  7158. (ÏZAdding Color With CopyBits(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  7159. currentdict /bu known {bu}if
  7160. userdict /_cv known not{userdict /_cv 30 dict put}if
  7161. _cv begin
  7162. /bdf{bind def}bind def
  7163. currentscreen/cs exch def/ca exch def/cf exch def
  7164. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7165. /ss{//cf //ca //cs setscreen}bdf
  7166. /stg{ss setgray}bdf
  7167. /strgb{ss setrgbcolor}bdf
  7168. /stcmyk{ss cvcmyk}bdf
  7169. /min1{dup 0 eq{pop 1}if}bdf
  7170. end
  7171. currentdict /bn known {bn}if
  7172. †ø∫◊#ˇ ˇˇˇˇ#◊ 
  7173. IR,Times
  7174. .+6-Macintosh Technical Notes /4/˘
  7175. °dONLNd)8ë*'Possible Problems
  7176. °dONLNdDPG*AThis colorizing will only work on 2-color (i.e. black and white) °dONLNdSDGP⁄(leimages, and then only if those°dONLNdrP\Ñ(x6colors occupy the first °dONLNdäPÑ\⁄)lKand last entries in the color table. Trying to colorize colors that are not°dONLNd÷\hF(Ñ6Ethe first and last color table entries will yield unexpected results.°dONLNdtÄm*LThis is mainly due to the fact that the colorizing algorithm uses a pixel’s °dONLNdhtmÄ⁄(úãcolor table index value°dONLNdÄÄå(®60rather than its actual RGB color. To illustrate °dONLNd∞Äå⁄)˜&this, let’s assume that foreground and°dONLNd◊åòy(¥6Fbackground colors are as above, and your image contains yellow with a °dONLNdåyò⁄(¥ócolor table index of°dONLNd2ò§Â(¿6*1000. The colorizing operation would give:,
  7177. Courier
  7178.     °dONLNd^∞<ªc+$;ColoredPixelValue = (NOT(1000) AND 0011) OR (1000 AND 1101)°dONLNdõ∫<≈c*
  7179. ;     1011         = (  0111    AND 0011) OR (1000 AND 1101)
  7180. °dONLNd◊–‹ï(¯6NSince the color table may have any RGB color at the resulting index position, °dONLNd%–ï‹⁄(¯≥the final color°dONLNd5‹Ëk(6Fmay not even be close to the source, foreground, or background colors.°dONLNd|Ùé*PSimilar things occur if you are trying to colorize a black and white image when °dONLNdÃÙé⁄(¨white and black°dONLNd‹ ,((6>do not occupy the first and last positions in the color table.°dONLNd%ê*The bottom line rules for °dONLNd5ê$»)xCopyBits°dONLNd=»%s)8%ing in a color environment are these:°dONLNdc1*=.(YH•°dONLNde17=º)
  7181. OThou shalt set thy background color to white and thy foreground color to black °dONLNd¥1º=⁄(Y⁄before°dONLNdª>7JY(fUcalling °dONLNd√=YIë)"CopyBits°dONLNdÀ>ëJ°)8 or °dONLNdœ=°IŸ)CopyMask°dONLNd◊>ŸJª)8., unless thou art coloring a monochrome image.°dONLNdV*b.(~H•°dONLNdV7b∂)
  7182. QThou shalt, when colorizing, make sure that the first color table entry is white °dONLNdYV∂b⁄(~‘and the°dONLNdab7nJ(äUlast °dONLNdgb`n◊))color table entry is black.°dONLNdÉzÜ.(¢6<The second rule is easy to follow because the default color °dONLNdøz.Ü⁄(¢L$tables are constructed properly, and°dONLNd‰Üív(Æ6if you are using the °dONLNd˘Üví⁄)^KPalette Manager (and you are, right?) then it will make sure that the color°dONLNdEíûz(∫6tables obey this rule.
  7183. °dONLNd\∂≈Í*'How To Colorize—An Example
  7184. °dONLNdw—›ò*This code fragment shows °dONLNdê—ò›⁄)ÄDhow to implement a color fill, like the paint bucket in MacPaint. It°dONLNd’fiÍü(6relies on three main things: °dONLNdÚ›üÈfi)á    SeedCFill°dONLNd˚fifiÍh)?  for calculating the fill area, °dONLNd›hȆ)äCopyMask°dONLNd#fi†Í∂)8 for °dONLNd(fi∂Í⁄)actually°dONLNd1͈Ô(6,changing the bits, and QuickDraw colorizing.
  7185.     °dONLNd^
  7186. :*:PROCEDURE PaintBucket(where: Point; paintColor: RGBColor);°dONLNdö<!K+$VAR°dONLNd† `+É+$
  7187. savedFG°dONLNd® ®+fl)H : RGBColor;°dONLNd∂*`5É(Q~offBits°dONLNdæ*®5’)H    : BitMap;°dONLNd…><IU(eZBEGIN°dONLNd—H`S+$
  7188. ${First, create an offscreen bitmap.}°dONLNd¯R`]*
  7189. %offBits.bounds := myWindow^.portRect;°dONLNd \`gÏ*
  7190. WITH offBits.bounds DO BEGIN°dONLNd@fÑqç+$
  7191. 5offBits.rowBytes := ((right - left + 15) DIV 16) * 2;°dONLNdypÑ{∞*
  7192. <offBits.baseAddr := NewPtr((bottom-top) * offBits.rowBytes);°dONLNd∏z`Öt(°~END;°dONLNdøé`ôZ*2{Check MemError here! Make sure NewPtr succeeded!} ◊4◊˘
  7193. (Ï62) of 3(ÏÇAdding Color With CopyBitsˇ    à◊#ˇ ˇˇˇˇ#◊ 
  7194. IR,Times
  7195. .+Z-Developer Support Center(-Ï
  7196. March 1988 /X/,
  7197. Courier
  7198.     °dONLNd'Ñ2ú(N¢8SeedCFill(myWindow^.portBits,offBits,myWindow^.portRect,°dONLNd<1®<z+$
  7199. *myWindow^.portRect,where.h,where.v,NIL,0);°dONLNdi;ÑFÚ(b¢GetForeColor(savedFG);°dONLNdÇEÑP*
  7200. RGBForeColor(paintColor);°dONLNdûOÑZø*
  7201. ?CopyMask(offBits,offBits,myWindow^.portBits,myWindow^.portRect,°dONLNd·Y®dk+$
  7202. 'myWindow^.portRect,myWindow^.portRect);°dONLNd cÑnÚ(ä¢RGBForeColor(savedFG);°dONLNd$wÑÇ*DisposPtr(offBits.BaseAddr);°dONLNdBÅ`åt(®~END;
  7203. °dONLNdGò<§É(¿Z
  7204. The variable °dONLNdTóÉ£¥)GoffBits°dONLNd[ò¥§)1 is an offscreen °dONLNdló£=)_BitMap°dONLNdrò=§E)* °dONLNdsòE§o)(not a °dONLNdzóo£ô)*PixMap°dONLNdÄòô§ƒ)*) with °dONLNdáóƒ£Ó)+bounds°dONLNdçòÓ§˛)* =°dONLNdê§<∞∫(ÕZmyWindow^.portRect°dONLNd¢•∫±»)~.  °dONLNd•§»∞)    SeedCFill°dONLNdÆ•±y)? effectively creates, in °dONLNd«•y±ø)rthe offscreen °dONLNd’§ø∞È)FBitMap°dONLNd€•ȱ˛)*,  a°dONLNd‡≤<æ_(⁄Z:monochrome image of the bits that we want to paint. Since °dONLNd±_Ωê(⁄}offBits°dONLNd!≤êæÌ)1 contains the exact °dONLNd5≤Ìæ˛)]bits°dONLNd:ø<Àõ(ÁZLthat we want to paint, it is used as both the source image and the mask for °dONLNdÜæõ ”(ÁπCopyMask°dONLNdéø”À◊)8.°dONLNdê◊<„(ˇZaBy setting the foreground color to the desired paint color, the result is a colorized version of °dONLNdÒ◊„˛(ˇthe°dONLNdı‰<•( Zmask (the paint area) °dONLNd ‰•J)ibeing copied onto the window’s °dONLNd*„JÔt)•PixMap°dONLNd0‰t˛)* without affecting any other°dONLNdM<¸Q(Zbits.°dONLNdS <,¶*0Further Reference: KXK°dONLNdf-N9R+
  7205. •°dONLNdh-`9¥)Color QuickDraw ◊X◊
  7206. (ÏZAdding Color With CopyBits(Ï3) of 3ˇÍ◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7207. /ZÅ#
  7208.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7209. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7210. .^ tK^ tK+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7211. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7212. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7213.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7214. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7215. IR.°dONLNd{<éœ(®Z+Deaccelerated _CopyBits & 8•24 GC QuickDraw
  7216. °dONLNd,ç<úr*Imaging°dONLNd4çoú˛(∏çM.IM.GCQDCopybits
  7217. °dONLNdF®<¥q(–Z Written by:°dONLNdR®Ñ¥›)HGuillermo A. Ortiz°dONLNde®∏¥˛(–÷
  7218. February 1991°dONLNds¡<Õ“(ÈZThis Technical Note discusses °dONLNdë¡“ÕV)ñconditions that may cause ,
  7219. Courier°dONLNd´¿VÃï)Ñ    _CopyBits°dONLNd¥¡ïÕ˛)? to slow down when°dONLNd«Õ<Ÿy(ıZ@QuickDraw acceleration is on via the Apple 8•24 GC Display Card. X
  7220. °dONLNd˛<
  7221. è*4 Introduction
  7222. °dONLNd<%ç*CWhen a drawing call is issued, GC IPC (Interprocess Communication) °dONLNdXç%˛(A´takes control of the call°dONLNdr%<1`(MZ=and passes it to GC QuickDraw.  After the normal port set up °dONLNdØ%`1˛(M~ (which involves caching the port°dONLNd–1<=›(YZ[parameters if this is the first drawing call after the port was set), GC QuickDraw returns °dONLNd+1›=˛(Y˚control°dONLNd3=<IY(eZ>to the application through the IPC and performs, in parallel, °dONLNdq=YI˛(ew!the drawing to its own monitor as°dONLNdìI<Uı(qZ$well as any other monitors that may °dONLNd∑IıU˛)π4be affected by  the operation.  The application then°dONLNdÏU<a“(}ZRcontinues its execution, probably issuing more drawing calls that get executed in °dONLNd>U“a˛(}the same°dONLNdGa<m®(âZasynchronous manner.°dONLNd\y<Ö›*YThe result of this mode of operation is improved performance, since the application gets °dONLNdµy›Ö˛(°˚control°dONLNdΩÖ<ë(≠Z0back immediately after issuing the call and the °dONLNdÌÖë˛)„(GC QuickDraw moves video data to its own°dONLNdë<ù1(πZ6video buffer as well as that of other cards in a more °dONLNdLë1ù˛)ı)rapid manner by using block transfers and°dONLNdvù<©0(≈Z3without requiring any action by the main processor.
  7223. °dONLNd™¡<–û*'._CopyBits Conforms To The Same Scheme, Except…
  7224. °dONLNdŸ‹<Ë{*    _CopyBits°dONLNd‚›{È)?" conforms to the same operational °dONLNd›È˛)¢-scheme, but there are some instances in which°dONLNd2È<ıâ(Z
  7225. GC QuickDraw °dONLNd?Èâı˛)MRcannot perform the call in parallel; in this cases it is even possible to suffer a°dONLNdíı<¿(Zperformance loss, since the °dONLNdÆı¿˛)Ñ@whole call may have to be completed before control is given back°dONLNdÔ<‚(*ZVto the application and GC QuickDraw has to make calls and access data across the NuBus
  7226.     °dONLNdE‚ Í('™
  7227. °dONLNdFÍÓ+.°dONLNdH<&∏(BZNThe situations that compromise GC QuickDraw parallel operation are as follows:°dONLNdó3N?R+•°dONLNdô3[?)
  7228. "When the destination device has a °dONLNdª2>I)®
  7229. SearchProc°dONLNd≈3I?¬)F installed and the source °dONLNdfl3¬?⁄)ycolor°dONLNdÂ?[Ko(gy:environment is different from the destination environment.°dONLNd!X[d∞*QuickDraw calls °dONLNd1X∞dª)Ua °dONLNd3Wªc)
  7230. SearchProc°dONLNd=Xd⁄)F) whenever the source and destination have°dONLNdgd[p(åy&different depths and when two indexed °dONLNdçdp⁄)¡'pixel maps have different color tables,°dONLNdµp[|˝(òy even though their depths may be °dONLNd’p˝|⁄)¢,identical.  When GC acceleration is enabled,°dONLNd|[àÿ(§ythese conditions cause the °dONLNd|ÿà⁄)}3following two types of behavior, dependent upon the°dONLNdQà[îÆ(∞ysource pixel map: ◊X◊
  7231. (ÏZ+Deaccelerated _CopyBits & 8•24 GC QuickDraw(Ï1) of 2ˇ°¿Ù%%DSIDICT:_cv
  7232. currentdict /bu known {bu}if
  7233. userdict /_cv known not{userdict /_cv 30 dict put}if
  7234. _cv begin
  7235. /bdf{bind def}bind def
  7236. currentscreen/cs exch def/ca exch def/cf exch def
  7237. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7238. /ss{//cf //ca //cs setscreen}bdf
  7239. /stg{ss setgray}bdf
  7240. /strgb{ss setrgbcolor}bdf
  7241. /stcmyk{ss cvcmyk}bdf
  7242. /min1{dup 0 eq{pop 1}if}bdf
  7243. end
  7244. currentdict /bn known {bn}if
  7245. †øv◊#ˇ ˇˇˇˇ#◊ 
  7246. IR,Times
  7247. .+6-Macintosh Technical Notes /4/˘
  7248. °dONLNd<)@+$•°dONLNdI)2)
  7249. /If the source is an indexed pixel map, then GC °dONLNd12)®)ÈQuickDraw executes the°dONLNdH*I6
  7250. (Rg,part of the setup that involves calling the ,
  7251. Courier°dONLNdt)
  7252. 5P)¡
  7253. SearchProc°dONLNd~*P6ü)F, returns control °dONLNdê*ü6®)Oto°dONLNdì6IB¿(^gthe main processor, then °dONLNd¨6¿B®)w3completes the call in parallel.  The act of calling°dONLNd‡CIO\(kgthe °dONLNd‰B\N¢)
  7254. SearchProc°dONLNdÓC¢O )F before returning control °dONLNdC O®)~makes the call slower than°dONLNd#PI\y(xgwhen no °dONLNd+Oy[ø)0
  7255. SearchProc°dONLNd5Pø\ƒ)F °dONLNd6Pƒ\®).is involved, since parallel operation does not°dONLNde\Ih‚(Ñg occur throughout the whole call.°dONLNdÜt<Ä@(úZ•°dONLNdàtIÄT)
  7256. If °dONLNdãtTÄ®) Cthe source is a direct RGB pixel map, then GC QuickDraw has to call°dONLNdœÅIçZ(©gthe °dONLNd”ÄZå†)
  7257. SearchProc°dONLNd›Å†ç¥)F for °dONLNd‚Å¥ç®)3every pixel that is drawn, and the application does°dONLNdéIöˇ(∂g+not regain control until after the call to °dONLNdAçˇô>)∂    _CopyBits°dONLNdJé>ö°)? has been completed.°dONLNd_ß*≥.(œH•°dONLNdaß7≥u)
  7258. DWhen the source or destination is offscreen and not created using a °dONLNd•¶u≤ü(œìGWorld°dONLNd´ßü≥£)*.°dONLNdÆø7ÀÁ(ÁU"GC QuickDraw has no way to detect °dONLNd–øÁÀ∂)∞*when an application is going to manipulate°dONLNd˚À7◊*(ÛU6a pixel map it has created in memory, so if it has to °dONLNd1À*◊∂)Ûdraw to or copy from such a°dONLNdM◊7„a(UPixMap°dONLNdSÿa‰‘)*, GC QuickDraw has to °dONLNdiÿ‘‰∂)s/complete the operation before returning control°dONLNdô‰7ã( Uto the application.°dONLNdÆ˝7    D*3This behavior is contrary to the case when using a °dONLNd·¸Dn(%bGWorld°dONLNdÁ˝n    ∂)* for offscreen°dONLNdˆ
  7259. 7~(2Uenvironments, °dONLNd
  7260. ~Ë)Gsince in the case of a °dONLNd    Ë)jGWorld°dONLNd!
  7261. ∂)* , GC QuickDraw is alerted by the°dONLNdB7#\(?Ucall to °dONLNdJ\"≈)%_GetPixBaseAddr°dONLNdY≈#É)i' that the application is getting ready °dONLNdÄÉ#∂)æ to directly°dONLNdå#7/    (KU.change the pixels.  This is the reason why it °dONLNd∫#    /∂)“&is so important that applications call°dONLNd·/7;†(XU_GetPixBaseAddr°dONLNd0†<£)i °dONLNdÒ0£<¬)every°dONLNdˆ0¬<‹) time °dONLNd¸0‹<q)they are about to manipulate a °dONLNd/q;õ)ïGWorld°dONLNd!0õ<∂)* pixel°dONLNd(<7Hu(dU
  7262. map directly.°dONLNd6U*a.(}H•°dONLNd8U7aè)
  7263. When the source °dONLNdHTè`π)XPixMap°dONLNdNUπaE)* has a color table that uses °dONLNdkUEa∂)åindexes that refer to a°dONLNdÉa7mY(âUpalette.°dONLNdçy7Öp*
  7264. QuickDraw °dONLNdóypÖ∂)9Enow allows a color table to have indexes that point to entries in the°dONLNd›Ü7íÖ(ÆUCpalette associated with the destination window; when bit 14 in the °dONLNd ÖÖë∂(Æ£ctFlags°dONLNd(í7û(∫U,field is set, the value fields in the color °dONLNdTíû∂)π+table are treated as palette entries.  When°dONLNdÄü7´X(«Usuch a °dONLNdáûX™Ç)!PixMap°dONLNdçüÇ´‘)* is the source for °dONLNd†û‘™)R    _CopyBits°dONLNd©ü´ù)?, then GC QuickDraw has to °dONLNdƒüù´∂)ämake°dONLNd…´7∑è(”Ua number of calls °dONLNd€´è∑∂)X<to the Palette Manager as part of the setup before returning°dONLNd∑7√À(flU control and completing the call.°dONLNd:–7‹W*9This case is similar to that of a indexed pixel map when °dONLNds–W‹b(¯ua °dONLNduœb€®)
  7265. SearchProc°dONLNd–®‹∂)F is°dONLNdÉ‹7Ëa(UDinvolved; therefore, it only implies a partial loss of parallelism; °dONLNd«‹aË∂(it is good to keep°dONLNd⁄È7ı5(U6in mind that this case can only occur when the source °dONLNdË5Ù_)˛PixMap°dONLNdÈ_ıñ)*  is indexed.°dONLNd#%Ç(A6Further Reference: D4D˘°dONLNd6&*2.+
  7266. •°dONLNd8&<2ç)Inside Macintosh°dONLNdH&ç2?)Q!, Volumes V & VI, Color QuickDraw°dONLNdj2*>.(ZH•°dONLNdl2<>s)
  7267. d e v e l o p°dONLNdy2s>∑)7@, “Macintosh Display Card 8•24 GC:  The Naked Truth,” July 1990.°dONLNd∫>*J.(fH•°dONLNdº><Jh)<Technical Note #275, 32-Bit QuickDraw:  Version 1.2 Features°dONLNd˘J*V.(rH•°dONLNd˚J<V≥)FDeveloper Notes for the Macintosh Display Cards 4•8, 8•24 and 8•24 GC °dONLNd    AJ≥V⁄(r—(APDA,°dONLNd    HV<b|(~Z
  7268. M085TLL/A)°dONLNd    SnzÍ(ñ6*NuBus is a trademark of Texas Instruments. ◊4◊˘
  7269. *V2) of 2)˙+Deaccelerated _CopyBits & 8•24 GC QuickDrawˇ¬◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7270. /ZÅ#
  7271.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7272. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7273. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7274. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7275. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7276.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7277. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7278. IR.°dONLNd{<é¥(®Z
  7279. Drawing Icons
  7280. °dONLNdç<úr*Imaging°dONLNdçxú˛(∏ñM.IM.DrawingIcons
  7281. °dONLNd(®<¥q(–Z Written by:°dONLNd4®Ñ¥Œ)HJim Friedlander°dONLNdD®æ¥˛(–‹ October 1985°dONLNdQ¡<ÕÚ(ÈZ$Using resources of type ICON allows °dONLNdu¡ÚÕU)∂drawing of icons in ,
  7282. Courier°dONLNdâ¿UÃx)csrcOr°dONLNdé¡xÕ˛)# mode.  Using resources of°dONLNd©Õ<ŸF(ıZ5type ICN# allows for more variety when drawing icons. X°dONLNdflÛ<ˇ>*&8There are two different kinds of resources that contain °dONLNdÛ>ˇØ(\icons: ICON and ICN#°dONLNd+ÚØ˛∂)q.°dONLNd,Û∂ˇ˛)
  7283.  An ICON is a°dONLNd:ˇ< È('Z[32 by 32 bit image of an icon and can be drawn using the following Toolbox Utilities calls:
  7284.     °dONLNdó`"Ò+$MyIconHndl:= GetIcon(iconID);°dONLNd∂!`,‚*
  7285. PlotIcon(destRect,iconID);
  7286. °dONLNd—7<Ci(_Z>While very convenient, this method only allows the drawing of °dONLNd7iC˛(_áicons in SrcOr mode (as in the°dONLNd.C<O≥(kZMiniFinder). The Finder °dONLNdFC≥O˛)wAuses resources of type ICN# to draw icons on the desktop. Because°dONLNdàO<[b(wZ>the Finder uses ICN#s, it can draw icons in a variety of ways.°dONLNd«g<sO*An °dONLNd gOs˛)PICN# resource is a list of 32 by 32 bit images that are grouped together. Common°dONLNds<˝(õZ'convention has been to group two 32 by °dONLNdBs˝˛)¡432 bit images together in each ICN#. The first image°dONLNdw<ã¢(ßZis the actual icon, the °dONLNdè¢ã˛)fEsecond image is the mask for the icon. To get a handle to an ICN#, we°dONLNd’ã<óÃ(≥Zwould use something like this:
  7287.     °dONLNdÙ£<ÆP*TYPE°dONLNd˙≠`∏›+$
  7288. iListHndl    = ^iListPtr;°dONLNd∑`¬Ï*
  7289. iListPtr     = ^iListStruct;°dONLNd3¡`Ã…*
  7290. iListStruct  = record°dONLNdKÀÑ÷B+$
  7291. &icon : packed array[0..31] of Longint;°dONLNdt’чB*
  7292. &mask : packed array[0..31] of Longint;°dONLNdúfl`Í∫(~End; {iListStruct}°dONLNdØÛ<˛K(ZVAR°dONLNd¥˝`‚+$
  7293. myILHndl      : iListHndl;°dONLNdœ˝w)ê        {handle to an ICN#}°dONLNdÏ`”(.~iBitMap       : BitMap;°dONLNdw)ê      {BitMap for the icon}°dONLNd!`”(8~mBitMap       : BitMap;°dONLNd9w)ê      {BitMap for the mask}°dONLNdV%`0_(L~3MyILHndl:= iListHndl(GetResource('ICN#',iconID));  °dONLNdç/`:*
  7294. #if MyILHndl = NIL then HandleError;°dONLNd¥9ÑD=+$
  7295. %{and exit or whatever is appropriate}
  7296. °dONLNd⁄O<[(wZ,Once we have a handle to the icons, we need °dONLNdO[˛)÷1to set up two bitMaps that we will be using later°dONLNd8\<hH(ÑZin °dONLNd;[HgÄ) CopyBits°dONLNdC\ÄhÉ)8:
  7297.     °dONLNdFt<P(õZ    °dONLNdKt`»)$HSetRect(icnRect,0,0,32,32);                { define the icon's 'bounds'}°dONLNdï~`â…*
  7298. With iBitMap do Begin°dONLNd´à<ìı(ØZ%         baseAddr:= @MyILHndl^^.icon;°dONLNd“í<ù™*
  7299.          rowbytes:= 4;°dONLNdÈíÃù)ê               °dONLNd˙í\ùù)ê
  7300.  { 4 * 8 =32}°dONLNdú<ßæ(√Z         bounds:= icnRect; ◊X◊
  7301. *)
  7302. Drawing Icons(Ï1) of 4ˇ°¿Ù%%DSIDICT:_cv
  7303. currentdict /bu known {bu}if
  7304. userdict /_cv known not{userdict /_cv 30 dict put}if
  7305. _cv begin
  7306. /bdf{bind def}bind def
  7307. currentscreen/cs exch def/ca exch def/cf exch def
  7308. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7309. /ss{//cf //ca //cs setscreen}bdf
  7310. /stg{ss setgray}bdf
  7311. /strgb{ss setrgbcolor}bdf
  7312. /stcmyk{ss cvcmyk}bdf
  7313. /min1{dup 0 eq{pop 1}if}bdf
  7314. end
  7315. currentdict /bn known {bn}if
  7316. †ø t◊#ˇ ˇˇˇˇ#◊ 
  7317. IR,Times
  7318. .+6-Macintosh Technical Notes /4/˘,
  7319. Courier
  7320.     °dONLNd(h*     End; {with}°dONLNd'2"*
  7321.   °dONLNd'<2•)$With mBitMap do Begin°dONLNd*1<—(X6%         baseAddr:= @MyILHndl^^.mask;°dONLNdP;FÜ*
  7322.          rowbytes:= 4;°dONLNdgEPö*
  7323.          bounds:= icnRect;°dONLNdÇOZ"*
  7324.   °dONLNdÖO<Zs)$ End; {with}
  7325. °dONLNdëeqq(ç6LIcons can represent desktop objects that are either selected or not. Folder °dONLNd›eqq⁄(çèand volume icons can°dONLNdÚq}†(ô6Seither be open or not. The object (or the volume it is on) can either be online or °dONLNdEq†}⁄(ôæ offline. The°dONLNdR}âh(•6GFinder draws icons using all permutations of open, selected and online:†09†Ç†é
  7326. ¿MD·ò4fii    fin¿M¸·Õ˙÷ˇ˙÷ˇ˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘#˙àĸÄx˛ˆ˚%˙à@¸ÄÑ˛¯˚*˙H‚¿O,˛ é,Ñ‚¿¯    ·≈IJ-˙I Hë2˛ë2Ñâ     ·≈Ä˚    &@˛-˙)'»Hë"˛ë"|Ñâ     &@˚    $@˛-˙) Hü"˛ë"ÑâÚ     $@˚    ‰@˛-˙ Hê"˛ë"Ñâ     ‰@˚    @˛-˙ Hë"˛ë"Ñâ     @˚    $@˛-˙‚ è"˛é"x‚     $@˚Ò·ƒ@˛#˙¸¸˚ÄÒ·ƒ@˚˚ ˙¸¸˚į˚˙ˆ¯¯˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ àįˆ˘0˙,à@0àÄ  0˙,H‚¿p„áÄà@  0˙,I àâë·«H‚¿p„á·p·‡0˙,)'«ààâë""I àâë"! 0˙,) Oà˘ë")'«ààâëÒ ! 0˙, HÅüÚ") Oà˘ë    Ò !Ú 0˙, Hàâëê" HÅ     ! 0˙,‚ áp‡«ë"" Hàâë    "! (˙ˆ ·¡é‚ áp‡«··‡˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘œˇœˇ˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚˛ˇ˛¸¯ˆ˘˚˛Ä¸¯ˆ˘#˚˛Ä¸˛ˇˇ¿ˆ˘#˚˛èˇÒ¸˛ˇˇ¿ˆ˘'˚˛ê    ¸˛¿ˆ‡˝+˚˛ïU    ¸˛
  7327. ˇ˛¿˛D˙∏˝+˚˛ê    ¸˛
  7328.  
  7329. U^¿˙.Ï˝,˚˛ïP    ¸˛
  7330.  
  7331. ˇ˛¿D˙
  7332. ;ªª∏+˚˛ê    ¸˛
  7333. U˛¿˝¸˝Ó-˚˛ï    ¸˛    
  7334. ˇ˛¿˛D¸˛ª∫.¿  ˛ê    ¸˛
  7335. _˛¿˝¸˝Ó0 ˛˛ï    ¸˛    
  7336. ˇ˛¿˛D¸˛ª∫.%Ñb√Ä˛ê    ¸˛
  7337. _˛¿˝¸˝Ó0&D#$@˛ï@    ¸˛    
  7338. ˇ˛¿˛D¸˛ª∫.$D"$@˛ê    ¸˛
  7339. W˛¿˝¸˝Óò4iV    nV¸M8·0$D"'¿˛ê    ¸˛    
  7340. ˇ˛¿˛D¸˛ª∫.$D"$˛èˇÒ¸˛
  7341. ˇ˛¿˝¸˝Ó0$D"$@˛Ä¸˛    ¿˛D¸˛ª∫.ƒD"#IJĸ˛ˇˇ¿˝¸˝Ó-˚˛Ä¸˛    ˇˇ¿˛D¸˛ª∫+˚˛Ä¸˛ˇˇ¿˝¸˝Ó-˚˛ÄÒ¸˛    ˇˇ¿˛D¸˛ª∫+˚˛Ä¸˛˛¿˝¸˝Ó-˚˛Ä¸˛    ˇˇ¿˛D¸˛ª∫+˚˛Ä¸˛ˇˇ¿˝¸˝Ó-˚˛Ä¸˛    ˇˇ¿˛D¸˛ª∫+˚˛ˇ˛¸˛ˇˇ¿˝¸˝Ó'˚˛@¸¯˛D¸˛ª∫'˚˛@¸˛ˇˇÄ˝¸˘#˚˛@¸˛ˇˇÄˆ˘#˚˛ˇ˛¸˛ˇˇÄˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘œˇœˇ˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚˛ˇ˛¸¯ˆ˘˚˛¢"#¸¯ˆ˘#˚˛àà⸲ ªªÄˆ˘#˚˛ØˇÛ¸˛ÓÓ¿ˆ˘#˚˛òà⸲
  7342. Ĉ˘#˚˛∑w+¸˛ ÓÓ¿ˆ˘'˚˛òà⸲    Äˆ‡˝+˚˛∑r+¸˛ ÓÓ¿˛D˙∏˝+˚˛òà⸲
  7343.     ∫Ä˙.Ï˝,˚˛∑"+¸˛
  7344. ÓÓ¿D˙
  7345. ;ªª∏.¡Üa˛òà⸲    ∫Ä˝¸˝Ó0" ˛∑"+¸˛     ÓÓ¿˛D¸˛ª∫.'#˛òà⸲    ∫Ä˝¸˝Ó0"!"˛∑b+¸˛     ÓÓ¿˛D¸˛ª∫."!"˛òà⸲    ∫Ä˝¸˝Ó0"!>˛≤"+¸˛     ÓÓ¿˛D¸˛ª∫."! ˛èˇ˘¸˛    ª∫Ä˝¸˝Ó0"!"˛¢"#¸˛    ¿˛D¸˛ª∫.¬!˛àà⸲ ªªÄ˝¸˝Ó-˚˛¢"#¸˛    ÓÓ¿˛D¸˛ª∫+˚˛àà⸲ ªªÄ˝¸˝Ó-˚˛¢/Û¸˛    ÓÓ¿˛D¸˛ª∫+˚˛àà⸲ ∫Ä˝¸˝Ó-˚˛¢"#¸˛    ÓÓ¿˛D¸˛ª∫+˚˛àà⸲ ªªÄ˝¸˝Ó-˚˛¢"#¸˛    ÓÓ¿˛D¸˛ª∫+˚˛ˇ˛¸˛ ªªÄ˝¸˝Ó'˚˛b""¸¯˛D¸˛ª∫+˚˛Hà串ªªÄ˝¸˝Óò4Vib    Vnb8MD·-˚˛b""¸˛    ÓÓIJD¸˛ª∫'˚˛ˇ˛¸˛ªªÄ˝¸˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘œˇœˇÕ†è†É
  7346. IR°dONLNdö=I—*¿XDrawing icons as non-open is basically the same for online and offline volumes. We need °dONLNdÚ=—I⁄(eÔto°dONLNdıIU∂(q6Xpunch a hole in the desktop for the icon. This is analogous to punching a hole in dough °dONLNdMI∂U⁄(q‘with an°dONLNdUUaM(}6Birregular shaped cookie-cutter. We can then sprinkle jimmies* all °dONLNdóUMa⁄(}kover the cookie and they will°dONLNdµam≈(â6Zonly stick in the area that we punched out (the mask). We do this by copyBitsing the mask °dONLNda≈m⁄(â„onto°dONLNdmyö(ï6Qthe desktop (whatever pattern) to our destRect. For non-open, non-selected icons:†Ç†é
  7347. ò˝¿0ò\(Ñ`\-Ñ`ò˝¿0˘˘˘˘˘˘˘ˇ˛˛Ä˛Ä˛èˇÒ˛ê    ˛ïU    ˛ê    ˛ïP    ˛ê    ˛ï    ˛ê    ˛ï    ˛ê    ˛ï@    ˛ê    ˛ê    ˛èˇÒ˛Ä˛Ä˛Ä˛Ä˛ÄÒ˛Ä˛Ä˛Ä˛Ä˛ˇ˛˛@˛@˛@˛ˇ˛˛˘˘†è†É
  7348. IR°dONLNdg≠π*@5we use the SrcBic mode so that we punch a white hole:
  7349.     °dONLNdû≈<–+$*SetRect(destRect,left,top,left+32,top+32);°dONLNd œ<⁄|*
  7350. @CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  7351. °dONLNd ÂÒî(
  7352. 6Then we XOR in the icon:
  7353.     °dONLNd%˝* °dONLNd'˝<|)$@CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXor,NIL);
  7354. °dONLNdh®(;6That’s all there is to drawing °dONLNdá®÷)ê:an icon as non-open, non-selected. To draw the icon as non°dONLNd¡÷⁄(;Ù-°dONLNd¬+^(G6open, selected:†Ç†é
  7355. JÚv;ò
  7356. —(˛x—.˛xJÚw<˜˜˜˜˜˜˜˜˜    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛¿8˛    ˛øˇÿ˛    ˛™´ÿ˛    ˛øˇÿ˛    ˛™øÿ˛    ˛øˇÿ˛    ˛´ˇÿ˛    ˛øˇÿ˛    ˛´ˇÿ˛    ˛øˇÿ˛    ˛™ˇÿ˛    ˛øˇÿ˛    ˛øˇÿ˛    ˛¿8˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇ¿8˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛˜˝ˇˇ˛˝ˇˇ˛˝ˇˇ˛˜˜˜˜˜˜˜†è†É
  7357. IR°dONLNd‹Wc *8Vwe will OR in the mask, causing a mask-shaped BLACK hole to be punched in the desktop:
  7358.     °dONLNd4o<zw+$?CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);
  7359. °dONLNduÖë (≠6$Then, as before, we XOR in the icon:
  7360.     °dONLNdõù<®|+$@CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXOr,NIL); ◊4◊˘
  7361. (Ï62) of 4(Ïæ
  7362. Drawing IconsˇŒ◊#ˇ ˇˇˇˇ#◊ 
  7363. IR,Times
  7364. .+Z-Developer Support Center, Palatino(-„ October 1985 0X0
  7365. °dONLNd*<6)(RZ0To draw icons as non-opened for offline volumes:†Ç†é
  7366. U!~Tò[(Ñ`[,Ñ_U!~T˘˘˘˘˘˘˘˘ˇ˛˛¢"#˛ààâ˛ØˇÛ˛òàâ˛∑w+˛òàâ˛∑r+˛òàâ˛∑"+˛òàâ˛∑"+˛òàâ˛∑b+˛òàâ˛≤"+˛èˇ˘˛¢"#˛ààâ˛¢"#˛ààâ˛¢/Û˛ààâ˛¢"#˛ààâ˛¢"#˛ˇ˛˛b""˛Hàä˛b""˛ˇ˛˛˘˘†è†É
  7367. IR°dONLNd1_<k/*51we need to do a little more work. We need to XOR °dONLNdb_/k˛)Û+a ltGray pattern into the boundsRect of the°dONLNdék<w~(ìZBicon. We will then punch the hole, draw the icon and then XOR out °dONLNd–k~w˛(ìúthe ltgray pattern that does°dONLNdÌw<ÉÍ(üZ[not fall inside the mask. So, to draw the icon as offline, non-open, non-selected we would:,
  7368. Courier
  7369.     °dONLNdJè`öƒ+$GetPenState(OldPen);°dONLNd`èöΩ)ê){save the pen state so we can restore it}°dONLNdãô`§∞(¿~PenMode(patXor);°dONLNdú£<ÆF( Z  °dONLNdü£`Æ´)$PenPat(ltGray);°dONLNdØ≠<∏F(‘Z  °dONLNd≤≠`∏ƒ)$PaintRect(destRect);°dONLNd»≠∏§)ê${paint a ltGray background for icon}°dONLNdÌ¡<ÃF(ËZ  °dONLNd¡`û)$HCopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); {punch}°dONLNd9À<÷A(ÚZ °dONLNd;À`÷»)$HPaintRect(destRect);{XOR out bits outside of the mask, leaving the mask}°dONLNdâ’Ç0+l
  7370. {filled with ltGray}°dONLNd´Í<ıA(Z °dONLNd–Ù<ˇ§*
  7371. HCopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);{ OR in }°dONLNdS˛\    ‘(%z{ the icon to the ltGray°dONLNdl<U(/Zmask}°dONLNdr<Æ*
  7372. JSetPenState(OldPen);                           {restore the old pen state}
  7373. °dONLNdΩ(<4*0To draw the icon as offline, non-open, selected:†Ç†é
  7374. SÇ]ò
  7375. À0˙xÀ4˙xSÇ]˜˜˜˜˜˜˜˜˜˜˜˜˜˛.ÓÓ˝˛;ªª˝˛(˝˛3ªª˝˛$Dj˝˛3ªª˝˛$FÍ˝˛3ªª˝˛$nÍ˝˛3ªª˝˛$nÍ˝˛3ªª˝˛$NÍ˝˛3ªª˝˛&ÓÍ˝˛8˝˛.ÓÓ˝˛;ªª˝˛.ÓÓ˝˛;ªª˝˛.Ë˝˛;ªª˝˛.ÓÓ˝˛;ªª˝˛.ÓÓ˝˜˛ÓÓ˝˛ª∫˝˛ÓÓ˝˜˜˜˜˜†è†É
  7376. IR°dONLNdÓc<o⁄*; we would use a similar approach:
  7377.     °dONLNd{<ÜP*    °dONLNd{`܃)$GetPenState(OldPen);°dONLNd*{ܬ)ê*{ save the pen state so we can restore it}°dONLNdVÖ`ê∞(¨~PenMode(patXor);°dONLNdhè`ö´*
  7378. PenPat(dkGray);°dONLNdyèö«)ê+{ the icon is selected, so we need dkGray }°dONLNd•ô<§F(¿Z  °dONLNd®ô`§ƒ)$PaintRect(destRect);°dONLNdæô§Æ)ê&{ paint a dkGray background for icon }°dONLNdÊ≠`∏(‘~ {punch a hole in the background}°dONLNd∑<¬F(fiZ  °dONLNd
  7379. ∑`¬†)$@CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);°dONLNdLÀ`÷ƒ*PaintRect(destRect);°dONLNdbÀ÷¬)ê*{XOR out bits outside of the mask, leaving°dONLNdí’‡Å*
  7380.  the mask filled with dkGray}°dONLNd±È`Ù(~!{BIC the icon to the dkGray mask}°dONLNd‘Û`˛†*
  7381. @CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);°dONLNd<F(.Z  °dONLNd`x)$8SetPenState(OldPen);         {restore the old pen state}
  7382. °dONLNdQ<*ä(FZCDrawing the opened icons requires one less step. We don’’t have to °dONLNdîä)¬(F®CopyBits°dONLNdú¬*ÿ)8 the °dONLNd°ÿ*˛)icon in,°dONLNd™*<6‚(RZ!we just use the mask. Online and °dONLNdÀ*‚6˛)¶6offline icons are drawn the same way. To draw icons as°dONLNd6<BÇ(^Zopen, selected:†Ç†é
  7383. aÉWòøN·éøT·åaÉW˘˘˘˘˘˘¿˝7p˝]ÿ˝    ˛wpˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ˘˘˘˘†è†É
  7384. IR°dONLNdd<pû*.we do the following:
  7385.     °dONLNd'|<áP*    °dONLNd,|`áƒ)$GetPenState(OldPen);°dONLNdB|áΩ)ê){save the pen state so we can restore it}°dONLNdlÜ<ëF(≠Z  °dONLNdoÜ`ë∞)$PenMode(patXor);°dONLNdÄê<õF(∑Z  °dONLNdÉê`õ´)$PenPat(dkGray);°dONLNdîêõ«)ê+{ the icon is selected, so we need dkGray }°dONLNd¿ö<•K(¡Z   °dONLNdƒö`•ƒ)$PaintRect(destRect);°dONLNd⁄ö•©)ê%{ paint a dkGray background for icon} ◊X◊
  7386. (ÏZ
  7387. Drawing Icons(Ï3) of 4ˇ–◊#ˇ ˇˇˇˇ#◊ 
  7388. IR,Times
  7389. .+6-Macintosh Technical Notes /4/˘,
  7390. Courier
  7391.     °dONLNd'<2‹+$! {punch a hole in the background}°dONLNd!1<"(X6  °dONLNd$1<<|)$@CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);°dONLNdeEP"(l6  °dONLNdkE<P™)$PaintRect(destRect);  °dONLNdÇEÃPû)ê*{XOR out bits outside of the mask, leaving°dONLNd≥OÃZX*
  7392. the mask filled with dkGray}°dONLNd–Yd"(Ä6  °dONLNd”Y<d†)$SetPenState(OldPen);°dONLNdÈYÃdS)ê{restore the old pen state}
  7393. °dONLNdo{»(ó6$To draw icons as open, non-selected:†Ç†é
  7394. ö˜∫6ò
  7395. fpÜ∏fsÜ≤ö˜∫6˜˜˜˜˜˜ ˚Ä˚" ˚˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝˜˜†è†É
  7396. IR°dONLNd*ß≥h*8Ewe just need to change one line from above. Instead of XORing with a °dONLNdoßh≥⁄(œÜdkGray pattern, we use°dONLNdÜ≥ød(€6a ltGray pattern:
  7397.     °dONLNdòÀ÷"*  °dONLNdõÀ<÷á)$PenPat(ltGray);°dONLNd¨ÀÃ÷ô)ê){icon is non-selected, so we need ltGray}
  7398. °dONLNd÷·Ì“(    6"These techniques will work on any °dONLNd¯·“Ì⁄)∫0background, window-white or desktop-gray and all°dONLNd)Ì˘™(6patterns in between. Have fun.°dONLNdH!*$* °dONLNdJ!I)    jimmies °dONLNdRI≥)(: little bits of chocolate°dONLNdmAMÇ(i6Further Reference: l4l˘°dONLNdÄN*Z.+
  7399. •°dONLNdÇN<Zr)    QuickDraw°dONLNdåZ*f.(ÇH•°dONLNdéZ<få)Toolbox Utilities ◊4◊˘
  7400. (Ï64) of 4(Ïæ
  7401. Drawing Iconsˇd◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7402. /ZÅ#
  7403.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7404. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7405. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7406. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7407. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7408.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7409. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7410. IR.°dONLNd{<éO(®ZDrawing Icons the System 7 Way
  7411. °dONLNdç<úr*Imaging°dONLNd'ç~ú˛(∏úM.IM.IconDrawing
  7412. °dONLNd8®<¥t(–Z Revised by:°dONLNdD®Ñ¥*)HDon Moccia and C.K. Haun <TR>°dONLNdb®æ¥˛(–‹ October 1992°dONLNdo¥<¿q(‹Z Written by:°dONLNd{¥Ñ¿)HJim Mensch and David Collins°dONLNdò¥æ¿˛(‹‹ October 1991°dONLNd•Ã<ÿO(ÙZ:This Technical Note describes how to utilize the built-in °dONLNdflÃOÿ˛(Ùm"System 7 icon drawing utility. Use°dONLNdÿ<‰ò(ZJthis information to better conform to the System 7 visual human interface.°dONLNdM<¸–*Changes since May 1992:°dONLNdd–¸‘)î6 In this Note, we replaced the C and Pascal interface °dONLNdö‘¸˛(Ú    files and°dONLNd§¸<Ω($ZOcorrected the related text. So much text was tweaked that change bars are used °dONLNdÛ¸Ω˛($€ only on code°dONLNd<f(0Zchanges. ?X?
  7413. °dONLNd
  7414. 9<Hè*4 Introduction
  7415. °dONLNdT<`*[With the introduction of System 7 for the Macintosh, Apple has defined a new look and feel °dONLNdrT`˛(|for°dONLNdv`<l`(àZ<many screen elements that better utilize color. Among those °dONLNd≤``l˛(à~ redefined elements are the icons°dONLNd”l<xÈ(îZUdrawn by the Finder and other system components. Until now, Apple has not documented °dONLNd(lÈx˛(îhow°dONLNd,x<Ñ/(†Z2to draw icons the way the Finder does in System 7.°dONLNd_ê<úö*MThis Technical Note discusses the icon toolkit calls that the Finder uses to °dONLNd¨êöú˛(∏∏draw and manipulate°dONLNd¿ù<©·(≈Z$the screen icons. Two of the calls, ,
  7416. Courier°dONLNd‰ú·®')•
  7417. PlotIconID°dONLNdÓù'©>)F and °dONLNdÛú>®ß)PlotCIconHandle°dONLNdùß©Æ)i, °dONLNdùÆ©˛)are the ones you°dONLNd©<µî(—Zwill probably use °dONLNd'©îµ˛)XHthe most since they simply deal with drawing single icons to the screen.°dONLNdpµ<¡∫(›ZSome parts of the toolbox°dONLNdâµ∫¡ø)~ °dONLNdäµø¡t)&require that an icon family handle be °dONLNd∞µt¡˛)µpassed to them to allow the°dONLNdá<Õë(ÈZdrawing of color °dONLNd›¡ëÕ˛)UJicons. The icon toolkit provides calls that allow you to create, draw, and°dONLNd(Õ<Ÿµ(ıZmanipulate these handles.
  7418. °dONLNdBÒ<|*'The New °dONLNdJÚ|†)@'ic'°dONLNdNÒ†
  7419. )$ Type Resources
  7420. °dONLNd^ <Ç(5Z
  7421. PlotIconID°dONLNdh
  7422. Çô)F and °dONLNdm ô)PlotCIconHandle°dONLNd|
  7423. ~)i allow the use of standard °dONLNdó ~®)|CIcons°dONLNdù
  7424. ®∏)* as °dONLNd°
  7425. ∏˛)
  7426. documented in°dONLNdØ<&ê(BZInside Macintosh °dONLNd¿ê&‹)TVolume V. The °dONLNdŒ‹%")L
  7427. PlotIconID°dONLNdÿ"&8)F call °dONLNdfi8&˛))also permits the use of a new set of icon°dONLNd&<2¥(NZresources documented in °dONLNd &¥2)xInside Macintosh °dONLNd1&2C)T Volume VI, °dONLNd<&C2˛);'Chapter 9. This new set is a collection°dONLNdd2<>‡(ZZ[of different icons, representing a single Finder object, into a family. Each member of the °dONLNdø2‡>˛(Z˛family°dONLNdΔ?<K·(gZ has the same resource ID as the °dONLNdÊ>·J )•'ICN#'°dONLNdÏ? K*)*, and °dONLNdÚ?*K˛)+a resource type indicating the icon data it°dONLNdK<Wª(sZPcontains. Currently Apple has defined three sizes of icons and three bit depths °dONLNdnKªW˛(sŸfor each size.°dONLNd}W<cb(Z@The sizes are large (32 by 32 pixels), small (16 by 16 pixels), °dONLNdΩWbc˛(Äand mini (12 by 12 pixels). The°dONLNd›c<ow(ãZEbit depths are 1, 4, and 8. The actual resource types are defined as:
  7428.     °dONLNd#{<ÜÕ*Large1BitMask    =    'ICN#';°dONLNdAÖ<êÕ*
  7429. Large4BitData    =    'icl4';°dONLNd_è<öÕ*
  7430. Large8BitData    =    'icl8';°dONLNd}ô<§Õ*
  7431. Small1BitMask    =    'ics#';°dONLNdõ£<ÆÕ*
  7432. Small4BitData    =    'ics4'; ◊X◊
  7433. *"Drawing Icons the System 7 Way(Ïˇ1, Palatino
  7434. ) 
  7435. )of 12ˇ°¿Ù%%DSIDICT:_cv
  7436. currentdict /bu known {bu}if
  7437. userdict /_cv known not{userdict /_cv 30 dict put}if
  7438. _cv begin
  7439. /bdf{bind def}bind def
  7440. currentscreen/cs exch def/ca exch def/cf exch def
  7441. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7442. /ss{//cf //ca //cs setscreen}bdf
  7443. /stg{ss setgray}bdf
  7444. /strgb{ss setrgbcolor}bdf
  7445. /stcmyk{ss cvcmyk}bdf
  7446. /min1{dup 0 eq{pop 1}if}bdf
  7447. end
  7448. currentdict /bn known {bn}if
  7449. †ø“◊#ˇ ˇˇˇˇ#◊ 
  7450. IR,Times
  7451. .+6-Macintosh Technical Notes /4/˘,
  7452. Courier
  7453.     °dONLNd(©*Small8BitData    =    'ics8';°dONLNd'2©*
  7454. Mini1BitMask     =    'icm#';°dONLNd<1<©*
  7455. Mini4BitData     =    'icm4';°dONLNdZ;F©*
  7456. Mini8BitData     =    'icm8';
  7457. °dONLNdxQ]£*RThe 1-bit-per-pixel member of each size also contains the mask data for all icons °dONLNd Q£]⁄(y¡ of that size°dONLNd◊]i](Ö6E(yes, this means that all your icons of a certain size must have the °dONLNd]]i÷(Ö{same mask). A 1-bit-per°dONLNd3]÷i⁄)y-°dONLNd4jv](í6
  7458. pixel member °dONLNdAj]v)E#must exist for each icon size that °dONLNddiuM)™
  7459. PlotIconID°dONLNdnjMv⁄)F uses. The icon size used is°dONLNdãvÇ∂(û6]determined by the size of the destination rectangle. If the destination rectangle is greater °dONLNdËv∂Ç⁄(û‘than 16°dONLNdÇé(™6:pixels on a side then the large icon will be used. If the °dONLNd*Çé⁄(™7(rectangle is 13–16 pixels on both sides,°dONLNdSéö (∂6)the small icon will be used. If it is 12 °dONLNd|é ö⁄)≤9or less on each side, the mini-icon will be used. The bit°dONLNd∂ö¶Ã(¬6%depth is determined by the device of °dONLNd€öö⁄)¥6the grafPort you plot into at drawing time. Be sure to°dONLNd¶≤&(Œ69create a color grafPort when you want to use color icons.
  7460. °dONLNdL Ÿ*'$Icon Families (or Suites and Caches °dONLNdp Ÿ⁄(ı;As the Tool Set Refers to°dONLNdäŸËC(6Them)
  7461. °dONLNdêÙ@*An icon °dONLNdòÙ@⁄)(Vfamily is simply a collection of icon handles that contain up to one image of each bit°dONLNdÔ q((6Jdepth and size for a given icon. The family can be fully populated (every °dONLNd9q ⁄((èpossible size or depth°dONLNdP e(46available), or it °dONLNdb e⁄)MJcan have only those icons that exist or are needed. By using families, you°dONLNd≠$T(@6@remove the need to determine which size or depth of icon to use °dONLNdÌT$⁄(@rwhen drawing into a given°dONLNd$0Δ(L6Vrectangle. Several system routines, the Notification Manager for example, can take an °dONLNd]$Δ0⁄(L‰icon°dONLNdb0<>(X6;family handle when an icon is requested. This permits them °dONLNdù0><⁄(X\ to use the proper color icons if°dONLNdæ<H≠(d6Xavailable. In the case of a sparsely populated icon family, when the proper icon is not °dONLNd<≠H⁄(dÀ
  7462. available,°dONLNd!HTD(p6Dthe icon toolkit will pick a substitute to produce the best results.°dONLNdfamÍ**An icon cache is a family that also has a °dONLNdê`Íl)“ProcPtr°dONLNdóam )1 °dONLNdòa mB)and a °dONLNdû`Bll)"refCon°dONLNd§alm⁄)*. The main difference°dONLNd∫myJ(ï6
  7463. between a °dONLNdƒmJy⁄)2Tcache and a family is that the elements of the cache’s array are sparsely populated.°dONLNdyÖL(°6BWhen using an icon cache, the system either will use the entry in °dONLNd[yLÖ⁄(°jthe icon family portion of the°dONLNdzÜí˙(Æ63cache or, if the desired element is empty, it will °dONLNd≠Ü˙í©)‚%call the procedure pointed to by the °dONLNd“Ö©ë⁄)ØProcPtr°dONLNd⁄íûw(∫6Land request the data for the icon. The procedure should have this interface:
  7464.     °dONLNd'™µ—*%FUNCTION IconGetter(theType: ResType;°dONLNdM¥ø˛*
  7465. .                    yourDataPtr: Ptr): Handle;
  7466. °dONLNd| ÷*7This function should return either the icon data to be °dONLNd≥ ÷⁄)˘*drawn or NIL to signify that this entry in°dONLNdfi÷‚@(˛6    the icon °dONLNdÁ÷@‚⁄)(Ucache does not exist. Icon caches can be used with all icon family calls. A few extra°dONLNd    =‚Óˇ(
  7467. 63calls are also available to manipulate icon caches.
  7468. °dONLNd    qÊ*'Drawing Modes or Transforms
  7469. °dONLNd    ç!-`*In addition to °dONLNd    ú!`-⁄)HHvarious sizes and bit depths, icons can be drawn with different modes or°dONLNd    Â-9å(U6transforms. Transforms °dONLNd    ¸-å9⁄)tFare analogous to certain Finder states for the icons. For example, the°dONLNd
  7470. C:F›(b6(transform that you would use to show an °dONLNd
  7471. k:›Fó)≈(icon of a disk that has been ejected is °dONLNd
  7472. ì9óE÷)∫    ttOffline°dONLNd
  7473. ú:÷F⁄)?.°dONLNd
  7474. ûFR÷(n6+Here is a list of the available transforms: ◊4◊˘
  7475. *~2) of 12(ÏqDrawing Icons the System 7 Wayˇ‹◊#ˇ ˇˇˇˇ#◊ 
  7476. IR,Times
  7477. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7478. Courier
  7479.     °dONLNd)<4“(PZttNone                =    $0;°dONLNd3<>“*
  7480. ttDisabled            =    $1;°dONLNd>=<H“*
  7481. ttOffline             =    $2;°dONLNd]G<R“*
  7482. ttOpen                =    $3;°dONLNd|Q<\·*
  7483. !ttSelected            =    $4000;°dONLNdû[<fE*
  7484. 5ttSelectedDisabled    =    (ttSelected + ttDisabled);°dONLNd‘e<p@*
  7485. 4ttSelectedOffline     =    (ttSelected + ttOffline);°dONLNd    o<z1*
  7486. 1ttSelectedOpen        =    (ttSelected + ttOpen);
  7487. °dONLNd;Ö<ë¶*The actual appearance °dONLNdQÖ¶ë˛)jDof the icon drawn by each transform type may vary with future system°dONLNdñë<ùË(πZ[software, so you should always use the transform that best fits the state it represents in °dONLNdÒëËù˛(πyour°dONLNdˆù<©å(≈ZHapplication. This way you will be consistent with future changes to the °dONLNd>ù婞(≈™look and feel of regular°dONLNdW™<∂Ø(“Zsystem icons. Note the °dONLNdn©Øµı)s
  7488. ttSelected°dONLNdx™ı∂{)F transform can be added to °dONLNdì™{∂˛)Üany of the other transform°dONLNdÆ∂<¬Y(fiZtypes.°dONLNdµŒ<⁄´*NThere are also transforms that use the Finder label colors to color the icon. °dONLNdŒ´⁄˛(ˆ…To determine the°dONLNd€<Á (Z3proper label for a file’s icon, you can check bits °dONLNdG€ ÁV)‰ 1–3 of the °dONLNdR⁄VÊá)6fdFlags°dONLNdY€áÁ˛)1 field in the file’s Finder°dONLNduÁ<Û(Zinfo. (See the °dONLNdÑÁÛ)CFinder Interface chapter in °dONLNd†ÁÛT)ÉInside Macintosh°dONLNd∞ÁTÛ˛)R! Volume VI for more information).°dONLNd“Ù<ê(ZFThese bits contain a number from 0 to 7. Simply add the corresponding °dONLNdÛêˇ»(ÆttLabel °dONLNd Ù»)8    value to °dONLNd)Ù˛)(the°dONLNd-< É((ZItransform that you give the call. The label values are defined like this:
  7489.     °dONLNdw<#Ø*ttLabel1    =    $0100;°dONLNdè"<-Ø*
  7490. ttLabel2    =    $0200;°dONLNdß,<7Ø*
  7491. ttLabel3    =    $0300;°dONLNdø6<AØ*
  7492. ttLabel4    =    $0400;°dONLNd◊@<KØ*
  7493. ttLabel5    =    $0500;°dONLNdÔJ<UØ*
  7494. ttLabel6    =    $0600;°dONLNdT<_Ø*
  7495. ttLabel7    =    $0700;
  7496. °dONLNdv<ÖÅ*&    Alignment
  7497. °dONLNd)ë<ùŸ*TMost icons do not fully fill their rectangle, and it is sometimes necessary to draw °dONLNd}ëŸù˛(π˜an icon°dONLNdÖù<©º(≈ZUrelative to other data (like menu text). In these instances it is nice to be able to °dONLNd⁄ùº©˛(≈⁄
  7498. have the icon°dONLNdË©<µg(—Zmove in °dONLNd©gµ˛)+Xits rectangle so that it will be at a predictable location in the destination rectangle.°dONLNdIµ<¡´(›ZCWhen drawing an icon you can pass one of these standard alignments °dONLNdåµ´¡˛(›…in the alignment°dONLNdù¡<Õ§(ÈZKparameter or you can add a vertical alignment to a horizontal alignment to °dONLNdË¡§Õ˛(Ȭcreate a composite°dONLNd˚Õ<Ÿä(ıZalignment value.
  7499.     °dONLNd Â<“*atNone                =    $0;°dONLNd+Ô<˙“*
  7500. atVerticalCenter      =    $1;°dONLNdJ˘<“*
  7501. atTop                 =    $2;°dONLNdi<“*
  7502. atBottom              =    $3;°dONLNdà
  7503. <“*
  7504. atHorizontalCenter    =    $4;°dONLNdß<"ã*
  7505. CatAbsoluteCenter      =    (atVerticalCenter + atHorizontalCenter);°dONLNdÎ!<,T*
  7506. 8atCenterTop           =    (atTop + atHorizontalCenter);°dONLNd$+<6c*
  7507. ;atCenterBottom        =    (atBottom + atHorizontalCenter);°dONLNd`5<@“*
  7508. atLeft                =    $8;°dONLNd?<JO*
  7509. 7atCenterLeft          =    (atVerticalCenter + atLeft);°dONLNd∑I<T*
  7510. ,atTopLeft             =    (atTop + atLeft);°dONLNd‰S<^'*
  7511. /atBottomLeft          =    (atBottom + atLeft);°dONLNd    ]<h“*
  7512. atRight               =    $C;°dONLNd    3g<rT*
  7513. 8atCenterRight         =    (atVerticalCenter + atRight);°dONLNd    lq<|*
  7514. -atTopRight            =    (atTop + atRight);°dONLNd    ö{<Ü,*
  7515. 0atBottomRight         =    (atBottom + atRight); ◊X◊
  7516. *JDrawing Icons the System 7 Way(Ïˇ3) of 12ˇH◊#ˇ ˇˇˇˇ#◊ 
  7517. IR,Times
  7518. .+6-Macintosh Technical Notes /4/˘
  7519. °dONLNd)8ë*'5And Now (Drum Roll Please) the Calls and What to Pass
  7520. °dONLNd6DPJ*<Now that we have defined every major data type we can think °dONLNdrDJP⁄(lhof, here are the actual toolkit°dONLNdíQ]˚(y60calls themselves. One word of caution: only the ,
  7521. Courier°dONLNd¬P˚\V)„
  7522. ForEachIconDo°dONLNdœQV]î)[ call protects °dONLNdfiQî]⁄)>the handle that°dONLNdÓ]i-(Ö6:is passed to it, so make your icon resources nonpurgeable.°dONLNd)uÅ}*Icon Family Calls
  7523.     °dONLNd;çò+*7FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  7524. °dONLNds£Øl* NewIconSuite°dONLNd§l∞£)TA returns an empty icon family handle with all members set to NIL.
  7525.     °dONLNd¡º«Ù(„6,FUNCTION AddIconToSuite(theIconData: Handle;°dONLNdÓΔ—Â*
  7526. )                        theSuite: Handle;°dONLNd–€
  7527. *
  7528. 1                        theType: ResType): OSErr;
  7529. °dONLNdJÁÛ¥*This call will add the data in °dONLNdiÊ¥Ú)ú theIconData°dONLNdtÁÛq)M into the suite at the °dONLNdãÁqÛ⁄)plocation reserved for°dONLNd°ÛˇI(6theType°dONLNd®ÙIí)1 of icon data. °dONLNd∑ÛíˇÙ)IAddIconToSuite°dONLNd≈ÙÙ`)b will replace any old °dONLNd€Ù`⁄)ldata in that slot without°dONLNdı
  7530. fl()6)disposing of it, so you may want to call °dONLNdfl O)«GetIconFromSuite°dONLNd.O
  7531. ⁄)p to obtain the old handle (if°dONLNdLB(66Bany) to dispose of it. This call will be used most often with the °dONLNdé
  7532. Bñ(6` NewIconSuite°dONLNdöñ⁄)T call to fill the°dONLNd¨&®(B6 empty family after it’s created.
  7533.     °dONLNdÕ2=*2FUNCTION GetIconFromSuite(VAR theIconData: Handle;°dONLNd<GÔ*
  7534. +                          theSuite: Handle;°dONLNd,FQ*
  7535. 3                          theType: ResType): OSErr;
  7536. °dONLNd`]iV*FThis call will return a handle to the pixel data of the family member °dONLNd¶]Vid(Ötof °dONLNd©\dhú)theSuite°dONLNd±]úi⁄)8
  7537.  specified by°dONLNdøiuI(í6theType°dONLNdΔjIvú)1. If you intend to °dONLNdŸjúvV)S(dispose of this handle, be sure to call °dONLNdiVu∏)∫AddIconToSuite°dONLNdj∏v⁄)b with a°dONLNdvÇ‘(û6(NIL handle to zero out the family entry.
  7538.     °dONLNd@éô‡*(FUNCTION ForEachIconDo(theSuite: Handle;°dONLNdiò£*
  7539. 3                       selector: IconSelectorValue;°dONLNdù¢≠Í*
  7540. *                       action: IconAction;°dONLNd»¨∑*
  7541. 0                       yourDataPtr: Ptr): OSErr;
  7542. °dONLNd˘√œö*This routine will call your °dONLNd¬öŒ‡)Ç
  7543. IconAction°dONLNd√‡œ)F  procedure °dONLNd*√œ⁄)7'(see below) for each icon in the family°dONLNdR–‹V(¯6
  7544. specified by °dONLNd_œV€é)>selector°dONLNdg–é‹í)8 °dONLNdh–í‹®)and °dONLNdlœ®€‡)theSuite°dONLNdt–‡‹)8. The °dONLNdzœ€8) selector°dONLNdÇ–8‹⁄)8# parameter is a bit-level flag that°dONLNd¶‹Ë≥(6specifies which family members °dONLNd≈‹≥Ë⁄)õ=to operate on; they can be added together to create composite°dONLNdËÙ§(6Uselectors that work on several different family members. The values for selector are:
  7545.     °dONLNdY ¬*"svLarge1Bit        =    $00000001;°dONLNd|
  7546. ¬*
  7547. "svLarge4Bit        =    $00000002;°dONLNdü¬*
  7548. "svLarge8Bit        =    $00000004;°dONLNd¬)¬*
  7549. "svSmall1Bit        =    $00000100;°dONLNdÂ(3¬*
  7550. "svSmall4Bit        =    $00000200;°dONLNd2=¬*
  7551. "svSmall8Bit        =    $00000400;°dONLNd+<G¬*
  7552. "svMini1Bit         =    $00010000;°dONLNdNFQ¬*
  7553. "svMini4Bit         =    $00020000;°dONLNdqP[¬*
  7554. "svMini8Bit         =    $00040000;°dONLNdîZe¬*
  7555. "svAllLargeData     =    $000000FF;°dONLNd∑do¬*
  7556. "svAllSmallData     =    $0000FF00;°dONLNd⁄ny¬*
  7557. "svAllMiniData      =    $00FF0000;°dONLNd˝xÉ]*
  7558. AsvAll1BitData      =    (svLarge1Bit + svSmall1Bit + svMini1Bit);°dONLNd    ?Çç]*
  7559. AsvAll4BitData      =    (svLarge4Bit + svSmall4Bit + svMini4Bit);°dONLNd    Ååó]*
  7560. AsvAll8BitData      =    (svLarge8Bit + svSmall8Bit + svMini8Bit);°dONLNd    √ñ°¬*
  7561. "svAllAvailableD    =    $FFFFFFFF; ◊4◊˘
  7562. */4) of 12(ÏqDrawing Icons the System 7 Wayˇö◊#ˇ ˇˇˇˇ#◊ 
  7563. IR,Times
  7564. .+Z-Developer Support Center(-Ê October 1992 /X/
  7565. °dONLNd<)˚(EZ*The action procedure that gets called for °dONLNd*˚)˛)ø7each icon type selected for the family is a Pascal type°dONLNdb)<5Î(QZ&function with the following interface:,
  7566. Courier
  7567.     °dONLNdâA<Lı*%FUNCTION IconAction(theType: ResType;°dONLNdØK<V*
  7568. (                    VAR theIcon: Handle;°dONLNdÿU<`*
  7569. -                    yourDataPtr: Ptr): OSErr;
  7570. °dONLNdl<xÜ*The parameter °dONLNdkÜw∑)JtheIcon°dONLNdl∑xX)1  is passed by reference here so °dONLNd;lXx˛)° that your routine can modify the°dONLNd\y<Ö‚(°Z$contents of the suite directly. The °dONLNdÄx‚Ñ7)¶ yourDataPtr °dONLNdåy7Ö˛)U¶meter is the value passed when you°dONLNd≥Ü<í\(ÆZcalled °dONLNd∫Ö\ë∑) 
  7571. ForEachIconDo°dONLNd«Ü∑íx)[&. It allows you to easily communicate °dONLNdÌÜxí˛)¡with your application. The°dONLNdì<ü◊(ªZaction procedure returns an °dONLNd$í◊û˙)õOSErr°dONLNd)ì˙üT)#. If any value °dONLNd8ìTüî)Z other than °dONLNdCíîû∑)@noErr°dONLNdHì∑ü˛)#
  7572.  is returned,°dONLNdVü<´ó(»Z
  7573. ForEachIconDo°dONLNdc†ó¨È)[F will stop processing immediately and return the error passed. (Note: °dONLNd©†Ȩ˛(»This°dONLNdƨ<∏·(‘Z$implies that the icons selected may °dONLNd“¨·∏˛)•;only be partially operated on. There is no guaranteed order°dONLNd∏<ƒÂ(‡Z$in which the icons get operated on.)
  7574.     °dONLNd3–<€'*/FUNCTION GetIconSuite(VAR theIconSuite: Handle;°dONLNdc⁄<Â*
  7575. (                      theResID: INTEGER;°dONLNdå‰<Ô^*
  7576. :                      selector: IconSelectorValue): OSErr;
  7577. °dONLNd«˙<ê* GetIconSuite°dONLNd”˚ê¸)T will create a new icon °dONLNdÎ˚¸˛)l7family and fill it from the current resource chain with°dONLNd#<µ(0Zthe icons of resource ID °dONLNd<µÌ)ytheResID°dONLNdDÌa)8 and types indicated by °dONLNd\aô)tselector°dONLNddôÏ)8. This is the call °dONLNdwÏ˛)Syou°dONLNd{<!á(=ZHwill probably use most often to create an icon family. Note that if you °dONLNd√á ˛(=•SetResLoad(False)°dONLNd’!<-Ø(IZQbefore making this call, the suite will be filled with unloaded resource handles.
  7578.     °dONLNd'9<Dı*%FUNCTION PlotIconSuite(theRect: Rect;°dONLNdMC<N,*
  7579. 0                       align: IconAlignmentType;°dONLNd~M<X@*
  7580. 4                       transform: IconTransformType;°dONLNd≥W<b@*
  7581. 4                       theIconSuite: Handle): OSErr;
  7582. °dONLNdËm<y*]This call renders the proper icon image from the passed icon family based on the bit depth of°dONLNdGy<Öœ* the display you are using and °dONLNdeyœÖ˛)ì<the rectangle that you have passed. The parameters align and°dONLNd¢Ö<ë(≠ZYtransform are applied to the icon selected for drawing and then the icon is plotted into °dONLNd˚Öë˛(≠the°dONLNdˇí<ûí(∫Zcurrent grafPort. °dONLNdëíùÌ)V
  7583. PlotIconSuite°dONLNdíÌûj)[ chooses the appropriate °dONLNd7íjû˛)}icon based primarily on size.°dONLNdUû<™Y(ΔZOnce °dONLNdZûY™˛)Tthe proper icon size is determined (based on the destination rectangle), the present°dONLNdØ™<∂ì(“ZKmember of that size with the deepest bit depth that the current device can °dONLNd˙™ì∂˛(“±use is selected. A size°dONLNd∑<√z(flZ category is °dONLNd∑z√–)>>considered present if the black-and-white member (with mask), °dONLNd\∂–¬˙(flÓ'ICN#'°dONLNdb∑˙√˛)*,°dONLNdd√<œf(ÏZ'ics#'°dONLNdjƒf–Ñ)*, or °dONLNdo√ÑœÆ)'icm#'°dONLNduƒÆ– )*, is °dONLNdzƒ –˘)    present. °dONLNdÉ√˘œT)/
  7584. PlotIconSuite°dONLNdêƒT–˛)[ can be used for both picture°dONLNdÆ–<‹∫(¯Zaccumulation and printing.
  7585.     °dONLNd…Ë<Û'*/FUNCTION DisposeIconSuite(theIconSuite: Handle;°dONLNd˘Ú<˝O*
  7586. 7                          disposeData: BOOLEAN): OSErr;
  7587. °dONLNd    1    <ì*This call disposes °dONLNd    D    ìh)W/the icon family handle itself. In addition, if °dONLNd    shµ)’ disposeData°dONLNd    ~    µ˛)M is true, any of°dONLNd    è<!∂(=ZRthe icon data handles that do not belong to a resource fork will also be disposed.
  7588.     °dONLNd    ‚-<8ã*CFUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  7589. °dONLNd
  7590. &C<Oª*TThis call allows you to specify a label to draw an icon of this suite when no label °dONLNd
  7591. zCªO˛(kŸis specified in°dONLNd
  7592. äO<[ó(xZ
  7593. PlotIconSuite°dONLNd
  7594. óPó\∑)[=. This is used primarily to ensure that a family passed to a °dONLNd
  7595. ‘P∑\˛(x’system routine°dONLNd
  7596. „\<hs(ÑZ gets drawn °dONLNd
  7597. Ó\sh˛)7Swith the proper label. The default label can be overridden by specifying a label in°dONLNd Bh<tó(ëZ
  7598. PlotIconSuite°dONLNd Oióuõ)[.
  7599.     °dONLNd QÅ<å6(®Z2FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  7600. °dONLNd Ñó<£ó*
  7601. GetSuiteLabel°dONLNd ëòó§E)[' returns the label previously set with °dONLNd ∏óE£†)Æ
  7602. SetSuiteLabel°dONLNd ≈ò†§§)[. ◊X◊
  7603. (ÏZDrawing Icons the System 7 Way(Ïˇ5) of 12ˇÃ◊#ˇ ˇˇˇˇ#◊ 
  7604. IR,Times
  7605. .+6-Macintosh Technical Notes /4/˘
  7606. °dONLNd)5x*$Icon Cache Calls°dONLNdAMu*NIn addition to the icon family calls, icon caches have these additional calls:,
  7607. Courier
  7608.     °dONLNdaYd˘*-FUNCTION MakeIconCache(VAR theHandle: Handle;°dONLNdècnÙ*
  7609. ,                       makeIcon: IconGetter;°dONLNdºmx!*
  7610. 5                       yourDataPtr: UNIV Ptr): OSErr;
  7611. °dONLNdÚÑê˜*1This call creates an empty icon cache similar to °dONLNd#ɘèK)fl NewIconSuite°dONLNd/ÑKêR)T, °dONLNd1ÑRê⁄)and associates the additional°dONLNdOêú(∏66icon loading procedure and data value with the family.
  7612.     °dONLNdÜ®≥—*%FUNCTION LoadIconCache(theRect: Rect;°dONLNd¨≤Ω*
  7613. 0                       align: IconAlignmentType;°dONLNd›º«*
  7614. 4                       transform: IconTransformType;°dONLNdΔ—*
  7615. 4                       theIconCache: Handle): OSErr;
  7616. °dONLNdG‹Ëê*This call allows preflight °dONLNdb‹êË⁄)xDloading of certain elements of your icon cache. This is handy if you°dONLNdßËÙ
  7617. (62suspect that certain drawing operations may occur °dONLNdŸË
  7618. Ù⁄)ı)at a time not convenient for loading your°dONLNdıc(6Ficon data (e.g., when your resource fork might not be in open chain). °dONLNdIÙcæ(Å
  7619. LoadIconCache°dONLNdVıæ⁄)[ takes°dONLNd]á(*6the same parameters as °dONLNdtá
  7620. ‚)o
  7621. PlotIconSuite°dONLNdÅ‚`)[ and uses the same criteria °dONLNdù`⁄)~to select the icon to load.°dONLNdπY(66
  7622. The grafPort °dONLNdΔY⁄)APmust be set properly before making this call since it is one of the criteria for°dONLNd&ü(B6determining the icon to load.°dONLNd53?—*&The following four calls are provided °dONLNd[3—?)π
  7623. to change °dONLNde2>6)4theData°dONLNdl36?J)1 or °dONLNdp2J>{)theProc°dONLNdw3{?⁄)1 associated with an°dONLNdã?KL(g6 icon cache:
  7624.     °dONLNdóWbÔ*+FUNCTION GetIconCacheData(theCache: Handle;°dONLNdƒal*
  7625. 3                          VAR theData: Ptr): OSErr;°dONLNd¯kvÔ*
  7626. +FUNCTION SetIconCacheData(theCache: Handle;°dONLNd%uÄ*
  7627. /                          theData: Ptr): OSErr;°dONLNdUäÔ*
  7628. +FUNCTION GetIconCacheProc(theCache: Handle;°dONLNdÇâî:*
  7629. :                          VAR theProc: IconGetter): OSErr;°dONLNdΩìûÔ*
  7630. +FUNCTION SetIconCacheProc(theCache: Handle;°dONLNdÍù®&*
  7631. 6                          theProc: IconGetter): OSErr;
  7632. °dONLNd!≥ø◊*"Plotting Icons Not Part of a Suite°dONLNdDÀ◊*5The next calls are grouped because they are similar. °dONLNdyÀ◊⁄)ˇ'They let you plot an icon to the screen°dONLNd°ÿ‰m(6Fwithout your creating an icon suite. They are also good if you have a °dONLNdÁ◊m„ó(ã'cicn'°dONLNdÌÿó‰¿)*     instead °dONLNdˆÿ¿‰⁄))of an°dONLNd¸‰Q( 6 icon family.
  7633.     °dONLNd    ¸¬*"FUNCTION PlotIconID(theRect: Rect;°dONLNd,˘*
  7634. -                    align: IconAlignmentType;°dONLNdZ
  7635. *
  7636. 1                    transform: IconTransformType;°dONLNdå%˛*
  7637. .                    theResID: INTEGER): OSErr;°dONLNdª.9€*'FUNCTION PlotCIconHandle(theRect: Rect;°dONLNd„8C*
  7638. 2                         align: IconAlignmentType;°dONLNdBM&*
  7639. 6                         transform: IconTransformType;°dONLNdMLW+*
  7640. 7                         theCIcon: CIconHandle): OSErr;°dONLNdÖ`k÷*&FUNCTION PlotIconMethod(theRect: Rect;°dONLNd¨ju
  7641. *
  7642. 1                        align: IconAlignmentType;°dONLNdfit!*
  7643. 5                        transform: IconTransformType;°dONLNd    ~â˛*
  7644. .                        theMethod: IconGetter;°dONLNd    Càì&*
  7645. 6                        yourDataPtr: UNIV Ptr): OSErr; ◊4◊˘
  7646. *=6) of 12(ÏqDrawing Icons the System 7 Wayˇ◊#ˇ ˇˇˇˇ#◊ 
  7647. IR,Times
  7648. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7649. Courier
  7650.     °dONLNd'<2˙(NZ&FUNCTION PlotIconHandle(theRect: Rect;°dONLNd'1<<1*
  7651. 1                        align: IconAlignmentType;°dONLNdY;<FE*
  7652. 5                        transform: IconTransformType;°dONLNdèE<P,*
  7653. 0                        theIcon: Handle): OSErr;°dONLNd¿Y<d˙*&FUNCTION PlotSICNHandle(theRect: Rect;°dONLNdÁc<n1*
  7654. 1                        align: IconAlignmentType;°dONLNdm<xE*
  7655. 5                        transform: IconTransformType;°dONLNdOw<Ç,*
  7656. 0                        theSICN: Handle): OSErr;
  7657. °dONLNdÄé<öj*
  7658. All these °dONLNdäéjö4).)routines share the following parameters: °dONLNd≥ç4ôn) theRect °dONLNdªénö˛):is the destination rectangle to°dONLNd€õ<߃(√Zdraw the indicated icon into; °dONLNd˘öƒ¶Á)àalign°dONLNd˛õÁß)# is the °dONLNdõ߲)4alignment method to use if the icon does not fit the°dONLNd;®<¥â(–Zrectangle given; °dONLNdLßâ≥»)M    transform°dONLNdU®»¥€)?< indicates the desired appearance of the icon on the screen.°dONLNdí¡<ÕJ(ÈZIn °dONLNdï¿JÃê)
  7659. PlotIconID°dONLNdü¡êÕ‹)F, the parameter °dONLNdØ¿‹Ã)LtheResID°dONLNd∑¡Õ$)8 is °dONLNdª¡$Õ…)!the resource ID of the family of °dONLNd‹¿…ÃÂ)•'ic'°dONLNd‡¡ÂÕ˛) type°dONLNdÊÕ<Ÿl(ıZ
  7660. resources °dONLNdÕlŸ˛)0Yto use. If the correct bit depth or the size required is not defined, the closest-fitting°dONLNdJŸ<Âç(Zone will be used.°dONLNd\Ú<˛T*The °dONLNd`ÒT˝Ω)PlotCIconHandle°dONLNdoÚΩ˛˜)i  parameter °dONLNdzÒ˜˝/):theCIcon°dONLNdÇÚ/˛N)8 is a °dONLNdàÚN˛˛)!handle that you get to a standard°dONLNd™ˇ< Œ('ZQuickDraw color icon. Unlike °dONLNd«˛Œ
  7661. 
  7662. )í    PlotCIcon°dONLNd–ˇ
  7663.  )?, °dONLNd“˛
  7664. })PlotCIconHandle°dONLNd·ˇ} ´)i
  7665.  does not °dONLNdΡ´ ˛).honor the current°dONLNd˝ <˝(4Z'foreground and background colors. Call °dONLNd$ ˝5)¡GetCIcon°dONLNd, 5˛)8) to load the icon. Dispose of it when you°dONLNdV<$>(@Z7are done, since they can take up quite a bit of memory.°dONLNdé0<<û*PlotIconMethod°dONLNdú1û=’)b  calls your °dONLNd®0’<)7
  7666. IconGetter°dONLNd≤1=V)F  procedure, °dONLNdæ1V=˛);#discussed earlier, to check for the°dONLNd‚=<I•(eZexistence of icon data.°dONLNd˚U<aû*PlotIconHandle°dONLNd    Vûb )b will plot the data from °dONLNd"V b)nan °dONLNd%UaE)'ICN#'°dONLNd+VEbW)* or °dONLNd/UWaÅ)'ICON'°dONLNd5VÅb˛)* resource from its handle.°dONLNdPc<o£(ãZIt is a new version of °dONLNdgb£n€)gPlotIcon°dONLNdoc€ofl)8.°dONLNdq{<áû(§ZPlotSICNHandle°dONLNd|ûà)b plots the data of a °dONLNdî{á-)e'SICN'°dONLNdö|-à2)* °dONLNdõ|2à‘)resource from its handle. Only °dONLNd∫{‘á˛)¢'SICN'°dONLNd¡à<î¡(∞ZLresources with a single member, or one in which the second member is a mask °dONLNd
  7667. à¡î˛(∞flfor the first,°dONLNdî<†ì(ºZwill plot correctly.°dONLNd1¨<∏;*9All the functions return an error code if things did not °dONLNdj¨;∏˛)ˇ(go well with the drawing or, in the case°dONLNdìπ<≈Z(·Zof the °dONLNdö∏Zƒ†)
  7668. PlotIconID°dONLNd§π†≈ë)F6 call, if the indicated icon family could not be used.°dONLNd€—<›≠(˘ZMiscellaneous Calls
  7669.     °dONLNdÔÈ<Ùˇ*'FUNCTION GetLabel(labelNumber: INTEGER;°dONLNdÛ<˛*
  7670. +                  VAR labelColor: RGBColor;°dONLNdC˝<6*
  7671. 2                  VAR labelString: Str255): OSErr;
  7672. °dONLNdv<=*:This call returns the actual color and string used in the °dONLNd∞=˛(;[(label menu of the Finder and the label’s°dONLNdŸ<+(GZ,Control Panel. This information is provided °dONLNd+˛)“3in case you wish to include the label text or color°dONLNd9+<7#(SZ2when displaying a file’s icon in your application.
  7673.     °dONLNdlC<N**FUNCTION IconSuiteToRgn(theRgn: RgnHandle;°dONLNdóM<Xˇ*
  7674. '                        iconRect: Rect;°dONLNdøW<b1*
  7675. 1                        align: IconAlignmentType;°dONLNdÒa<lE*
  7676. 5                        theIconSuite: Handle): OSErr;°dONLNd    'u<ġ*'FUNCTION IconIDToRgn(theRgn: RgnHandle;°dONLNd    O<ä*
  7677. $                     iconRect: Rect;°dONLNd    tâ<î"*
  7678. .                     align: IconAlignmentType;°dONLNd    £ì<û*
  7679. -                     iconID: INTEGER): OSErr; ◊X◊
  7680. *2Drawing Icons the System 7 Way(Ïˇ7) of 12ˇ§◊#ˇ ˇˇˇˇ#◊ 
  7681. IR,Times
  7682. .+6-Macintosh Technical Notes /4/˘,
  7683. Courier
  7684.     °dONLNd(Ô*+FUNCTION IconMethodToRgn(theRgn: RgnHandle;°dONLNd,'2‡*
  7685. (                         iconRect: Rect;°dONLNdU1<*
  7686. 2                         align: IconAlignmentType;°dONLNdà;F*
  7687. /                         theMethod: IconGetter;°dONLNd∏EP*
  7688. 2                         yourDataPtr: Ptr): OSErr;
  7689. °dONLNdÎ\h`*These routines °dONLNd˙\`hç)H?will create a region from the mask of the icon selected by the °dONLNd9[çg≈(Ñ´iconRect°dONLNdA\≈h⁄)8 and°dONLNdFht;(ë6align°dONLNdKi;u¡)#T values passed. They will allow you to do accurate hit testing and outline dragging °dONLNdüi¡u⁄(ëflof an°dONLNd•vÇW(û6
  7690. icon in your °dONLNd≤vWÇ™)?application. The °dONLNd√u™ÅÈ)S    RgnHandle°dONLNdÃvÈÇ⁄)?/ must have been previously allocated before you°dONLNd¸Çé\(™6make this call.
  7691.     °dONLNd ö•‡*(FUNCTION RectInIconSuite(testRect: Rect;°dONLNd5§؇*
  7692. (                         iconRect: Rect;°dONLNd^Æπ*
  7693. 2                         align: IconAlignmentType;°dONLNdë∏√0*
  7694. 8                         theIconSuite: Handle): BOOLEAN;°dONLNd Ã◊—*%FUNCTION RectInIconID(testRect: Rect;°dONLNd÷·—*
  7695. %                      iconRect: Rect;°dONLNd‡Î*
  7696. /                      align: IconAlignmentType;°dONLNdFÍı*
  7697. 0                      iconID: INTEGER): BOOLEAN;°dONLNdw˛    Â*)FUNCTION RectInIconMethod(testRect: Rect;°dONLNd°Â*
  7698. )                          iconRect: Rect;°dONLNdÀ*
  7699. 3                          align: IconAlignmentType;°dONLNdˇ'*
  7700. 0                          theMethod: IconGetter;°dONLNd0&1!*
  7701. 5                          yourDataPtr: Ptr): BOOLEAN;°dONLNdf:E—*%FUNCTION PtInIconSuite(testPt: Point;°dONLNdåDO÷*
  7702. &                       iconRect: Rect;°dONLNd≥NY*
  7703. 0                       align: IconAlignmentType;°dONLNd‰Xc&*
  7704. 6                       theIconSuite: Handle): BOOLEAN;°dONLNdlw¬*"FUNCTION PtInIconID(testPt: Point;°dONLNd>vÅ«*
  7705. #                    iconRect: Rect;°dONLNdbÄã˘*
  7706. -                    align: IconAlignmentType;°dONLNdêäï˛*
  7707. .                    iconID: INTEGER): BOOLEAN;°dONLNdøû©÷*&FUNCTION PtInIconMethod(testPt: Point;°dONLNdÊ®≥€*
  7708. '                        iconRect: Rect;°dONLNd≤Ω
  7709. *
  7710. 1                        align: IconAlignmentType;°dONLNd@º«˛*
  7711. .                        theMethod: IconGetter;°dONLNdoΔ—*
  7712. 3                        yourDataPtr: Ptr): BOOLEAN;
  7713. °dONLNd£‹Ë*.These calls hit test the passed Point or Rect °dONLNd—‹Ë⁄)È*against the icon indicated. The parameters°dONLNd¸ËÙP(6iconRect°dONLNdÈPıg)8 and °dONLNd    ËgÙä)align°dONLNdÈäı∏)#@, and the grafPort should be the same as when the icon was last °dONLNdNÈ∏ı⁄(÷drawn.°dONLNdUı\(6The functions °dONLNdcı\⁄)DTreturn true if the point is in the icon mask or if the rectangle intersects the icon°dONLNd∏
  7714. 5()6mask.
  7715. °dONLNdæ%4k*' Error Codes
  7716. °dONLNd @Lõ*RThe Icon Utilities will pass back any errors encountered during execution, so you °dONLNd@õL⁄(hπ
  7717. can expect to°dONLNd*LXW(t6>see Memory Manager, Resource Manager, and other normal errors.°dONLNdidpÆ* There is one error code defined °dONLNdâdÆp⁄)ñAspecifically for the Icon Utilities routines that may be returned°dONLNdÀp|°(ò6by the Icon plotting routines. ◊4◊˘
  7718. *T8) of 12(ÏqDrawing Icons the System 7 Wayˇé◊#ˇ ˇˇˇˇ#◊ 
  7719. IR,Times
  7720. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7721. Courier
  7722.     °dONLNd)<4n(PZ
  7723. { Pascal }°dONLNd 3<>U*
  7724. CONST°dONLNd=`Hƒ+$
  7725. noMaskFound = -1000;°dONLNd'G<RP(nZEND;°dONLNd,[<f_*/* C */°dONLNd4e<põ*
  7726. #define noMaskFound°dONLNdHe®p¡)l-1000
  7727. °dONLNdN{<á≈(£ZThis error will be returned if °dONLNdm{≈á˛)âBthe Icon Utilities package could not find or create a mask for the°dONLNd∞á<ìH(ØZ;icon family.  The Icon Utilities will use the correct mask °dONLNdÎáHì˛(Øf(for each icon size, if one is available.°dONLNdì<ü&(ªZ4If no mask for a specific size is available, a mask °dONLNdIì&ü˛)Í,will be created from any mask in the family,°dONLNdvü<´¸(«Zebut if there are no 1 bit images and no mask in the family, plotting calls will fail with this error.
  7728. °dONLNd‹√<“7*'$Type(def)s and Glue for Pascal and C
  7729. °dONLNdfi<Ífi* The Pascal and C interfaces are °dONLNd!fifiͲ)¢5provided here to copy and paste since the current MPW°dONLNdWÍ<ˆí(Zstandard interface °dONLNdjÍíˆ˛)VOfiles do not contain the glue for these calls. Electronic versions of this note°dONLNd∫ˆ<R(Zare °dONLNdæˆR˛)Mon AppleLink (Developer Support: Developer Services: Technical Documentation:°dONLNd </(*Z.Macintosh Technical Notes: Imaging: Graphics: °dONLNd:/˛)Û(Icon Drawing in 7.sit (Stuffit)) and the°dONLNdc<â(6ZBDeveloper CD (Technical Documentation: Macintosh Technical Notes: °dONLNd•â˛(6ßImaging: Graphics: Icon°dONLNdΩ<&Ç(BZDrawing in 7).°dONLNdÃ2<>Œ*QMPW C, Pascal, and Assembler files also have been submitted to AppleLink and the °dONLNd2Œ>˛(ZÏ    Developer°dONLNd'><Jl(fZ>CD, but their paths were not known when this note was written.
  7730.     °dONLNdfV<aå*{ Pascal Types }°dONLNdwj<uö*FIconAction         =  ProcPtr;  {FUNCTION IconAction(theType: ResType;°dONLNdæt<©*
  7731. I                                                     VAR theIcon: Handle;°dONLNd~<â«*
  7732. O                                                     yourDataPtr: Ptr): OSErr;}°dONLNdXà<ìö*
  7733. FIconGetter         =  ProcPtr;  {FUNCTION IconGetter(theType: ResType;°dONLNdüí<ùÃ*
  7734. P                                                     yourDataPtr: Ptr): Handle;}°dONLNdú<ß“*
  7735. IconSelectorValue  =  LONGINT;°dONLNd¶<±“*
  7736. IconAlignmentType  =  INTEGER;°dONLNd.∞<ª“*
  7737. IconTransformType  =  INTEGER;°dONLNdMƒ<œá*{ Pascal Glue }°dONLNd]ÿ<„ü*GFUNCTION PlotIconID(theRect: Rect; align: IconAlignmentType; transform:°dONLNd•‚<Ìñ*
  7738. IconTransformType;°dONLNd∏Ï<˜"*
  7739. .                    theResID: INTEGER): OSErr;°dONLNdÁˆ<ı*
  7740. %         INLINE  $303C, $0500, $ABC9;°dONLNd
  7741. < O*
  7742. 7FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;°dONLNdE
  7743. <ı*
  7744. %         INLINE  $303C, $0207, $ABC9;°dONLNdk<—*
  7745. QFUNCTION AddIconToSuite(theIconData: Handle; theSuite: Handle; theType: ResType):°dONLNdΩ<)Z*
  7746. OSErr;°dONLNdƒ(<3ı*
  7747. %         INLINE  $303C, $0608, $ABC9;°dONLNdÍ2<=A*
  7748. F°dONLNdÎ2A=F)U°dONLNdÏ2F=K)N°dONLNdÌ2K=P)C°dONLNdÓ2P=U)T°dONLNdÔ2U=Z)I°dONLNd2Z=_)O°dONLNdÒ2_=d)N°dONLNdÚ2d=i) °dONLNdÛ2h=m)G°dONLNdÙ2m=r)e°dONLNdı2r=w)t°dONLNdˆ2w=|)I°dONLNd˜2|=Å)c°dONLNd¯2Å=Ü)o°dONLNd˘2Ü=ã)n°dONLNd˙2ã=ê)F°dONLNd˚2ê=ï)r°dONLNd¸2ï=ö)o°dONLNd˝2ö=ü)m°dONLNd˛2ü=§)S°dONLNdˇ2§=©)u°dONLNd2©=Æ)i°dONLNd2Æ=≥)t°dONLNd2≥=∏)e°dONLNd2∏=Ω)(°dONLNd2Ω=¬)V°dONLNd2¬=«)A°dONLNd2«=Ã)R°dONLNd2Ã=—) °dONLNd2–=’)t°dONLNd    2’=⁄)h°dONLNd
  7749. 2⁄=fl)e°dONLNd 2fl=‰)I°dONLNd 2‰=È)c°dONLNd
  7750. 2È=Ó)o°dONLNd2Ó=Û)n°dONLNd2Û=¯)D°dONLNd2¯=˝)a°dONLNd2˝=)t°dONLNd2=)a°dONLNd2= ):°dONLNd2 =) °dONLNd2=)H°dONLNd2=)a°dONLNd2= )n°dONLNd2 =%)d°dONLNd2%=*)l°dONLNd2*=/)e°dONLNd2/=4);°dONLNd24=9) °dONLNd29=>)t°dONLNd2>=C)h°dONLNd2C=H)e°dONLNd 2H=M)S°dONLNd!2M=R)u°dONLNd"2R=W)i°dONLNd#2W=\)t°dONLNd$2\=a)e°dONLNd%2a=f):°dONLNd&2f=k) °dONLNd'2k=p)H°dONLNd(2p=u)a°dONLNd)2u=z)n°dONLNd*2z=)d°dONLNd+2=Ñ)l°dONLNd,2Ñ=â)e°dONLNd-2â=é);°dONLNd.2é=ì) °dONLNd/2ì=ò)t°dONLNd02ò=ù)h°dONLNd12ù=¢)e°dONLNd22¢=ß)T°dONLNd32ß=¨)y°dONLNd42¨=±)p°dONLNd52±=∂)e°dONLNd62∂=ª):°dONLNd8<<GA(cZR°dONLNd9<AGF)e°dONLNd:<FGK)s°dONLNd;<KGP)T°dONLNd<<PGU)y°dONLNd=<UGZ)p°dONLNd><ZG_)e°dONLNd?<_Gd))°dONLNd@<dGi):°dONLNdA<iGn) °dONLNdB<nGs)O°dONLNdC<sGx)S°dONLNdD<xG})E°dONLNdE<}GÇ)r°dONLNdF<ÇGá)r°dONLNdG<áGå);°dONLNdIF<Qı(mZ%         INLINE  $303C, $0609, $ABC9;°dONLNdoP<[Ω*
  7751. MFUNCTION ForEachIconDo(theSuite: Handle; selector: IconSelectorValue; action:°dONLNdΩZ<es*
  7752. IconAction;°dONLNd…d<o,*
  7753. 0                       yourDataPtr: Ptr): OSErr;°dONLNd˙n<yı*
  7754. %         INLINE  $303C, $060A, $ABC9;°dONLNd     x<ÉÜ*
  7755. BFUNCTION GetIconSuite(VAR theIconSuite: Handle; theResID: INTEGER;°dONLNd    cÇ<ç^*
  7756. :                      selector: IconSelectorValue): OSErr;°dONLNd    ûå<óı*
  7757. %         INLINE  $303C, $0501, $ABC9;°dONLNd    ƒñ<°Ω*
  7758. MFUNCTION DisposeIconSuite(theIconSuite: Handle; disposeData: BOOLEAN): OSErr;°dONLNd
  7759. †<´ı*
  7760. %         INLINE  $303C, $0302, $ABC9; ◊X◊
  7761. *%Drawing Icons the System 7 Way(Ïˇ9) of 12ˇh◊#ˇ ˇˇˇˇ#◊ 
  7762. IR,Times
  7763. .+6-Macintosh Technical Notes /4/˘,
  7764. Courier
  7765.     °dONLNd(ä*JFUNCTION PlotIconSuite(theRect: Rect; align: IconAlignmentType; transform:°dONLNdK'2r*
  7766. IconTransformType;°dONLNd^1<*
  7767. 4                       theIconSuite: Handle): OSErr;°dONLNdì;FÃ*
  7768. $        INLINE  $303C, $0603, $ABC9;°dONLNd∏EPg*
  7769. CFUNCTION MakeIconCache(VAR theHandle: Handle; makeIcon: IconGetter;°dONLNd¸OZ!*
  7770. 5                       yourDataPtr: UNIV Ptr): OSErr;°dONLNd2Yd—*
  7771. %         INLINE  $303C, $0604, $ABC9;°dONLNdXcnä*
  7772. JFUNCTION LoadIconCache(theRect: Rect; align: IconAlignmentType; transform:°dONLNd£mxr*
  7773. IconTransformType;°dONLNd∂wÇ*
  7774. 4                       theIconCache: Handle): OSErr;°dONLNdÎÅå—*
  7775. %         INLINE  $303C, $0606, $ABC9;°dONLNdãñX*
  7776. @FUNCTION PlotIconMethod(theRect: Rect; align: IconAlignmentType;°dONLNdRï†î*
  7777. L                        transform: IconTransformType; theMethod: IconGetter;°dONLNdüü™&*
  7778. 6                        yourDataPtr: UNIV Ptr): OSErr;°dONLNd◊©¥—*
  7779. %         INLINE  $303C, $0805, $ABC9;°dONLNd˝≥æ]*
  7780. AFUNCTION GetLabel(labelNumber: INTEGER; VAR labelColor: RGBColor;°dONLNd?Ω»*
  7781. 2                  VAR labelString: Str255): OSErr;°dONLNdr«“—*
  7782. %         INLINE  $303C, $050B, $ABC9;°dONLNdò—‹î*
  7783. LFUNCTION PtInIconID(testPt: Point; iconRect: Rect; align: IconAlignmentType;°dONLNd€Ê˛*
  7784. .                    iconID: INTEGER): BOOLEAN;°dONLNdÂ—*
  7785. %         INLINE  $303C, $060D, $ABC9;°dONLNd:Ô˙£*
  7786. OFUNCTION PtInIconSuite(testPt: Point; iconRect: Rect; align: IconAlignmentType;°dONLNdä˘&*
  7787. 6                       theIconSuite: Handle): BOOLEAN;°dONLNd¡—*
  7788. %         INLINE  $303C, $070E, $ABC9;°dONLNdÁ
  7789. ®*
  7790. PFUNCTION PtInIconMethod(testPt: Point; iconRect: Rect; align: IconAlignmentType;°dONLNd8"ä*
  7791. J                        theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;°dONLNdÉ!,—*
  7792. %         INLINE  $303C, $090F, $ABC9;°dONLNd©+6£*
  7793. OFUNCTION RectInIconID(testRect: Rect; iconRect: Rect; align: IconAlignmentType;°dONLNd˘5@*
  7794. 0                      iconID: INTEGER): BOOLEAN;°dONLNd*?J—*
  7795. %         INLINE  $303C, $0610, $ABC9;°dONLNdPIT≤*
  7796. RFUNCTION RectInIconSuite(testRect: Rect; iconRect: Rect; align: IconAlignmentType;°dONLNd£S^0*
  7797. 8                         theIconSuite: Handle): BOOLEAN;°dONLNd‹]h—*
  7798. %         INLINE  $303C, $0711, $ABC9;°dONLNdgr∑*
  7799. SFUNCTION RectInIconMethod(testRect: Rect; iconRect: Rect; align: IconAlignmentType;°dONLNdVq|î*
  7800. L                          theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;°dONLNd£{Ü—*
  7801. %         INLINE  $303C, $0912, $ABC9;°dONLNd…Öê≠*
  7802. QFUNCTION IconIDToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;°dONLNdèö˘*
  7803. -                     iconID: INTEGER): OSErr;°dONLNdIô§—*
  7804. %         INLINE  $303C, $0913, $ABC9;°dONLNdo£Æº*
  7805. TFUNCTION IconSuiteToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;°dONLNdƒ≠∏!*
  7806. 5                        theIconSuite: Handle): OSErr;°dONLNd˙∑¬—*
  7807. %         INLINE  $303C, $0914, $ABC9;°dONLNd     ¡Ãb*
  7808. BFUNCTION IconMethodToRgn(theRgn: RgnHandle; iconRect: Rect; align:°dONLNd    cÀ÷r*
  7809. IconAlignmentType;°dONLNd    v’‡Ö*
  7810. I                         theMethod: IconGetter; yourDataPtr: Ptr): OSErr;°dONLNd    ¿flÍ—*
  7811. %         INLINE  $303C, $0915, $ABC9;°dONLNd    ÊÈÙg*
  7812. CFUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;°dONLNd
  7813. *Û˛—*
  7814. %         INLINE  $303C, $0316, $ABC9;°dONLNd
  7815. P˝*
  7816. 2FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;°dONLNd
  7817. É—*
  7818. %         INLINE  $303C, $0217, $ABC9;°dONLNd
  7819. ©q*
  7820. EFUNCTION GetIconCacheData(theCache: Handle; VAR theData: Ptr): OSErr;°dONLNd
  7821. Ô&—*
  7822. %         INLINE  $303C, $0419, $ABC9;°dONLNd %0]*
  7823. AFUNCTION SetIconCacheData(theCache: Handle; theData: Ptr): OSErr;°dONLNd W/:—*
  7824. %         INLINE  $303C, $041A, $ABC9;°dONLNd }9Dî*
  7825. LFUNCTION GetIconCacheProc(theCache: Handle; VAR theProc: IconGetter): OSErr;°dONLNd  CN—*
  7826. %         INLINE  $303C, $041B, $ABC9;°dONLNd MXÄ*
  7827. HFUNCTION SetIconCacheProc(theCache: Handle; theProc: IconGetter): OSErr;°dONLNd 9Wb—*
  7828. %         INLINE  $303C, $041C, $ABC9;°dONLNd _alX*
  7829. @FUNCTION PlotIconHandle(theRect: Rect; align: IconAlignmentType;°dONLNd †kvû*
  7830. N                        transform: IconTransformType; theIcon: Handle): OSErr;°dONLNd ÔuÄ—*
  7831. %         INLINE  $303C, $061D, $ABC9;°dONLNd
  7832. äX*
  7833. @FUNCTION PlotSICNHandle(theRect: Rect; align: IconAlignmentType;°dONLNd
  7834. Vâîû*
  7835. N                        transform: IconTransformType; theSICN: Handle): OSErr;°dONLNd
  7836. •ìû—*
  7837. %         INLINE  $303C, $061E, $ABC9;°dONLNd
  7838. Àù®]*
  7839. AFUNCTION PlotCIconHandle(theRect: Rect; align: IconAlignmentType; ◊4◊˘
  7840. *(10)
  7841.  of 12(ÏqDrawing Icons the System 7 Wayˇ4◊#ˇ ˇˇˇˇ#◊ 
  7842. IR,Times
  7843. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7844. Courier
  7845.     °dONLNd<(¬(DZN                         transform: IconTransformType; theCIcon: CIconHandle):°dONLNdO'<2Z*
  7846. OSErr;°dONLNdV1<<ı*
  7847. %         INLINE  $303C, $061F, $ABC9;°dONLNd|O<Zå*/* C Typedefs */°dONLNdçc<n≥*Ktypedef pascal OSErr   (*IconAction)(ResType theType, Handle *theIcon, void°dONLNdŸm<xÇ*
  7848. *yourDataPtr);°dONLNdËw<Ç©*
  7849. Itypedef pascal Handle  (*IconGetter)(ResType theType, void *yourDataPtr);°dONLNd2Å<å    *
  7850. )typedef unsigned long  IconSelectorValue;°dONLNd\ã<ñ    *
  7851. )typedef short          IconAlignmentType;°dONLNdÜï<†    *
  7852. )typedef short          IconTransformType;°dONLNd∞©<¥x* /* C Glue */°dONLNdΩΩ<»ï*Epascal OSErr PlotIconID(const Rect *theRect, IconAlignmentType align,°dONLNd«<“ê*
  7853. D                        IconTransformType transform, short theResID)°dONLNdH—<‹Î*
  7854. #       =  {0x303C, 0x0500, 0xABC9};°dONLNdl€<Ê'*
  7855. /pascal OSErr NewIconSuite(Handle *theIconSuite)°dONLNdúÂ<Î*
  7856. #       =  {0x303C, 0x0207, 0xABC9};°dONLNd¿Ô<˙—*
  7857. Qpascal OSErr AddIconToSuite(Handle theIconData, Handle theSuite, ResType theType)°dONLNd˘<Î*
  7858. #       =  {0x303C, 0x0608, 0xABC9};°dONLNd6<‡*
  7859. Tpascal OSErr GetIconFromSuite(Handle *theIconData, Handle theSuite, ResType theType)°dONLNdã
  7860. <Î*
  7861. #       =  {0x303C, 0x0609, 0xABC9};°dONLNdØ<"÷*
  7862. Rpascal OSErr ForEachIconDo(Handle theSuite, IconSelectorValue selector, IconAction°dONLNd!<,_*
  7863. action,°dONLNd
  7864. +<6*
  7865. -                           void *yourDataPtr)°dONLNd85<@Î*
  7866. #       =  {0x303C, 0x080A, 0xABC9};°dONLNd\?<J—*
  7867. Qpascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, IconSelectorValue°dONLNdÆI<Ti*
  7868.     selector)°dONLNd∏S<^Î*
  7869. #       =  {0x303C, 0x0501, 0xABC9};°dONLNd‹]<hü*
  7870. Gpascal OSErr DisposeIconSuite(Handle theIconSuite, Boolean disposeData)°dONLNd$g<rÎ*
  7871. #       =  {0x303C, 0x0302, 0xABC9};°dONLNdHq<|§*
  7872. Hpascal OSErr PlotIconSuite(const Rect *theRect, IconAlignmentType align,°dONLNdë{<Ü∏*
  7873. L                           IconTransformType transform, Handle theIconSuite)°dONLNdfiÖ<êÎ*
  7874. #       =  {0x303C, 0x0603, 0xABC9};°dONLNdè<öü*
  7875. Gpascal OSErr MakeIconCache(Handle *theHandle, IconGetter makeIcon, void°dONLNdJô<§}*
  7876.  
  7877. *yourDataPtr)°dONLNdX£<ÆÎ*
  7878. #       =  {0x303C, 0x0604, 0xABC9};°dONLNd|≠<∏§*
  7879. Hpascal OSErr LoadIconCache(const Rect *theRect, IconAlignmentType align,°dONLNd≈∑<¬∏*
  7880. L                           IconTransformType transform, Handle theIconCache)°dONLNd¡<ÃÎ*
  7881. #       =  {0x303C, 0x0606, 0xABC9};°dONLNd6À<÷©*
  7882. Ipascal OSErr PlotIconMethod(const Rect *theRect, IconAlignmentType align,°dONLNdÄ’<‡¬*
  7883. N                            IconTransformType transform, IconGetter theMethod,°dONLNdœfl<Í"*
  7884. .                            void *yourDataPtr)°dONLNd˛È<ÙÎ*
  7885. #       =  {0x303C, 0x0805, 0xABC9};°dONLNd"Û<˛÷*
  7886. Rpascal OSErr GetLabel(short labelNumber, RGBColor *labelColor, Str255 labelString)°dONLNdu˝<Î*
  7887. #       =  {0x303c, 0x050B, 0xABC9};°dONLNdô<‡*
  7888. Tpascal Boolean PtInIconID(Point testPt, Rect *iconRect, IconAlignmentType alignment,°dONLNdÓ<ˇ*
  7889. '                          short iconID)°dONLNd    <&Î*
  7890. #       =  {0x303c, 0x060D, 0xABC9};°dONLNd    :%<0∏*
  7891. Lpascal Boolean PtInIconSuite(Point testPt, Rect *iconRect, IconAlignmentType°dONLNd    á/<:n*
  7892.  
  7893. alignment,°dONLNd    í9<D1*
  7894. 1                             Handle theIconSuite)°dONLNd    ƒC<NÎ*
  7895. #       =  {0x303c, 0x070E, 0xABC9};°dONLNd    ËM<XΩ*
  7896. Mpascal Boolean PtInIconMethod(Point testPt, Rect *iconRect, IconAlignmentType°dONLNd
  7897. 6W<bn*
  7898.  
  7899. alignment,°dONLNd
  7900. Aa<lö*
  7901. F                              IconGetter theMethod, void *yourDataPtr)°dONLNd
  7902. àk<vÎ*
  7903. #       =  {0x303c, 0x090F, 0xABC9};°dONLNd
  7904. ¨u<ÄΩ*
  7905. Mpascal Boolean RectInIconID(Rect *testRect, Rect *iconRect, IconAlignmentType°dONLNd
  7906. ˙<än*
  7907.  
  7908. alignment,°dONLNd â<î    *
  7909. )                            short iconID)°dONLNd /ì<ûÎ*
  7910. #       =  {0x303c, 0x0610, 0xABC9}; ◊X◊
  7911. *2Drawing Icons the System 7 Way(Ï˙11)
  7912.  of 12ˇ^◊#ˇ ˇˇˇˇ#◊ 
  7913. IR,Times
  7914. .+6-Macintosh Technical Notes /4/˘,
  7915. Courier
  7916.     °dONLNd(®*Ppascal Boolean RectInIconSuite(Rect *testRect, Rect *iconRect, IconAlignmentType°dONLNdQ'2J*
  7917.  
  7918. alignment,°dONLNd\1<*
  7919. 3                               Handle theIconSuite)°dONLNdê;F«*
  7920. #       =  {0x303c, 0x0711, 0xABC9};°dONLNd¥EP≠*
  7921. Qpascal Boolean RectInIconMethod(Rect *testRect, Rect *iconRect, IconAlignmentType°dONLNdOZJ*
  7922.  
  7923. alignment,°dONLNdYdÄ*
  7924. H                                IconGetter theMethod, void *yourDataPtr)°dONLNdZcn«*
  7925. #       =  {0x303c, 0x0912, 0xABC9};°dONLNd~mxî*
  7926. Lpascal OSErr IconIDToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType°dONLNdÀwÇJ*
  7927.  
  7928. alignment,°dONLNd÷Åå÷*
  7929. &                         short iconID)°dONLNd˝ãñ«*
  7930. #       =  {0x303c, 0x0613, 0xABC9};°dONLNd!*
  7931. Opascal OSErr IconSuiteToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType°dONLNdqü™J*
  7932.  
  7933. alignment,°dONLNd|©¥*
  7934. 0                            Handle theIconSuite)°dONLNd≠≥æ«*
  7935. #       =  {0x303c, 0x0714, 0xABC9};°dONLNd—Ω»®*
  7936. Ppascal OSErr IconMethodToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType°dONLNd"«“J*
  7937.  
  7938. alignment,°dONLNd-—‹q*
  7939. E                             IconGetter theMethod, void *yourDataPtr)°dONLNds€Ê«*
  7940. #       =  {0x303c, 0x0915, 0xABC9};°dONLNdóÂ?*
  7941. ;pascal OSErr SetSuiteLabel(Handle theSuite, short theLabel)°dONLNd”Ô˙«*
  7942. #       =  {0x303C, 0x0316, 0xABC9};°dONLNd˜˘Ô*
  7943. +pascal short GetSuiteLabel(Handle theSuite)°dONLNd#«*
  7944. #       =  {0x303C, 0x0217, 0xABC9};°dONLNdG
  7945. N*
  7946. >pascal OSErr GetIconCacheData(Handle theCache, void **theData)°dONLNdÜ"«*
  7947. #       =  {0x303C, 0x0419, 0xABC9};°dONLNd™!,I*
  7948. =pascal OSErr SetIconCacheData(Handle theCache, void *theData)°dONLNdË+6«*
  7949. #       =  {0x303C, 0x041A, 0xABC9};°dONLNd 5@g*
  7950. Cpascal OSErr GetIconCacheProc(Handle theCache, IconGetter *theProc)°dONLNdP?J«*
  7951. #       =  {0x303C, 0x041B, 0xABC9};°dONLNdtITb*
  7952. Bpascal OSErr SetIconCacheProc(Handle theCache, IconGetter theProc)°dONLNd∑S^«*
  7953. #       =  {0x303C, 0x041C, 0xABC9};°dONLNd€]hÖ*
  7954. Ipascal OSErr PlotIconHandle(const Rect *theRect, IconAlignmentType align,°dONLNd%grÄ*
  7955. H                            IconTransformType transform, Handle theIcon)°dONLNdnq|«*
  7956. #       =  {0x303C, 0x061D, 0xABC9};°dONLNdí{ÜÖ*
  7957. Ipascal OSErr PlotSICNHandle(const Rect *theRect, IconAlignmentType align,°dONLNd‹ÖêÄ*
  7958. H                            IconTransformType transform, Handle theSICN)°dONLNd%èö«*
  7959. #       =  {0x303C, 0x061E, 0xABC9};°dONLNdIô§ä*
  7960. Jpascal OSErr PlotCIconHandle(const Rect *theRect, IconAlignmentType align,°dONLNdî£Æ£*
  7961. O                             IconTransformType transform, CIconHandle theCIcon)°dONLNd‰≠∏«*
  7962. #       =  {0x303C, 0x061F, 0xABC9};
  7963. °dONLNd€ÁÇ*/Further Reference: 4˘°dONLNdË*Ù.+
  7964. •°dONLNdË<Ùç)Inside Macintosh°dONLNd-ËçÙ&)Q, Volume V, QuickDraw chapter°dONLNdKÙ*.(H•°dONLNdMÙ<ç)Inside Macintosh°dONLNd]Ùç?)Q%, Volume VI, Finder Interface chapter ◊4◊˘
  7965. (Ï612)
  7966.  of 12(ÏqDrawing Icons the System 7 Wayˇn◊#ˇ ˇˇˇˇ#◊†Ç 
  7967. /ZÅ#
  7968.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7969. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7970. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7971. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7972. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7973.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7974. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  7975. IR.°dONLNdˇˇ(ßZDisplaying Large PICT Files
  7976. °dONLNdˇˇ*Imaging°dONLNdˇˇ(∑±M.IM.LargePict
  7977. °dONLNdˇˇ(œZ Revised by:°dONLNdˇˇ(œ„
  7978. March 1988°dONLNdˇˇ(€Z Written by:°dONLNdˇˇ)H Rick Blair °dONLNdˇˇ(€Ì    July 1987°dONLNdˇˇ(ÛZ>Now that we have scanners and other massive-picture producing °dONLNdˇˇ(Ûétypes of applications, there is°dONLNdˇˇ(ˇZ(a need to address the problem of how to °dONLNdˇˇ)…2display a PICT format object that is bigger than a°dONLNdˇˇ( ZAcurrent PICT resource is allowed to be. Note that this technique °dONLNdˇˇ( âapplies equally well to version°dONLNdˇˇ(ZG1 and version 2 (word-opcode) pictures as produced by the Macintosh II. &X&
  7979. °dONLNdˇˇ*4Future Compatibility
  7980. °dONLNdˇˇ*"Think of the handle returned by a ,
  7981. Courier°dONLNdˇˇ)ßGetResource('PICT',ID)°dONLNdˇˇ)ö as a “handle” °dONLNdˇˇ)H in the more°dONLNdˇˇ(pZMgeneral sense of being an abstract “tag”—something that the ROM routines can °dONLNdˇˇ(p—use to draw the°dONLNdˇˇ(|ZPpicture with. Don’t assume that the entire picture has been read into memory or °dONLNdˇˇ(|fl that you can°dONLNdˇˇ(âZ)directly read any bytes beyond the basic °dONLNdˇˇ)ΔPicture°dONLNdˇˇ)1 record structure (°dONLNdˇˇ)ZpicSize°dONLNdˇˇ)1  followed by°dONLNdˇˇ(ñZpicFrame°dONLNdˇˇ)8:). Someday we may provide a mechanism for the resource to °dONLNdˇˇ(ñøbe disk- instead of°dONLNdˇˇ(¢ZLmemory-based. The QuickDraw bottleneck procedures will know how to get data °dONLNdˇˇ(¢› from and put°dONLNdˇˇ(ÆZ#data into the pictures in any case.
  7982. °dONLNdˇˇ*'Spooling from a PICT file
  7983. °dONLNdˇˇ**In order to display pictures of arbitrary °dONLNdˇˇ)»1size, your application should be able to import a°dONLNdˇˇ(˘ZQuickDraw picture from a °dONLNdˇˇ)~Afile of type PICT. This is the file produced by a “Save as…” from°dONLNdˇˇ(Z&MacDraw with the PICT option selected.°dONLNdˇˇ*?What follows is a small program fragment that demonstrates how °dONLNdˇˇ(õto spool in a picture from°dONLNdˇˇ()Z[the data fork °dONLNdˇˇ)BQof] a PICT file. The picture can be larger than the historical 32K resource size.°dONLNdˇˇ(6Z6See technical note #88 if you are unfamiliar with the °dONLNdˇˇ(6\Signal°dONLNdˇˇ)* mechanism. We assume that °dONLNdˇˇ)ëa°dONLNdˇˇ(CZ CatchSignals°dONLNdˇˇ)T has been done before °dONLNdˇˇ)jGetandDrawPICTFile
  7984. °dONLNdˇˇ)~ 
  7985. °dONLNdˇˇ)
  7986. is called.
  7987. °dONLNdˇˇ(jZMPW Pascal Example
  7988.     °dONLNdˇˇ+$1{the following variable must be at the top level}°dONLNdˇˇ*VAR°dONLNdˇˇ*
  7989. @   globalRef   : INTEGER;      {refNum of the file to read from}°dONLNdˇˇ*2{the following procedure must be at the top level}°dONLNdˇˇ*8PROCEDURE GetPICTData(dataPtr: Ptr; byteCount: INTEGER); ◊X◊
  7990. (ÏZDisplaying Large PICT Files(Ï1) of 5ˇ°¿Ù%%DSIDICT:_cv
  7991. currentdict /bu known {bu}if
  7992. userdict /_cv known not{userdict /_cv 30 dict put}if
  7993. _cv begin
  7994. /bdf{bind def}bind def
  7995. currentscreen/cs exch def/ca exch def/cf exch def
  7996. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7997. /ss{//cf //ca //cs setscreen}bdf
  7998. /stg{ss setgray}bdf
  7999. /strgb{ss setrgbcolor}bdf
  8000. /stcmyk{ss cvcmyk}bdf
  8001. /min1{dup 0 eq{pop 1}if}bdf
  8002. end
  8003. currentdict /bn known {bn}if
  8004. †ø◊#ˇ ˇˇˇˇ#◊ 
  8005. IR,Times
  8006. .+6-Macintosh Technical Notes /4/˘,
  8007. Courier
  8008.     °dONLNd<(6+$2{replacement for the QuickDraw bottleneck routine}°dONLNd41<<Z*   VAR°dONLNd<;<Fæ*
  8009.       err         : OSErr;°dONLNdXE<P»*
  8010.       longCount   : LONGINT;°dONLNdvY<dd*   BEGIN°dONLNdÄc<nÕ*
  8011.       longCount := byteCount;°dONLNdüm<x1*
  8012. 1      err := FSRead(globalRef,longCount,dataPtr);°dONLNd“w<Çü*
  8013. G      {can't check for an error because we don't know how to handle it}°dONLNdÅ<å_*
  8014.    END;°dONLNd$ï<†U*CONST°dONLNd+ü<™Ü*
  8015. B   abortPICT    = 128;         {error code if DrawPicture aborted}°dONLNdo≥<æ©*IPROCEDURE GetDrawPICTFile;     {read in a PICT FILE selected by the user}°dONLNd∫«<“Z*   VAR°dONLNd¬—<‹T*
  8016. 8      wher        : Point;     {where to display dialog}°dONLNd¸€<Ê*
  8017. -      reply       : SFReply;   {reply record}°dONLNd+Â<h*
  8018. <      myFileTypes : SFTypeList; {more Standard FILE goodies}°dONLNdiÔ<˙»*
  8019.       numFileTypes: INTEGER;°dONLNdá<◊*      savedProcs  : QDProcsPtr;°dONLNd®
  8020. <|*
  8021. @      myProcs     : QDProcs;   {use CQDProcs for a color window}°dONLNdÍ!<,©*I      myPicture   : PicHandle; {we need a picture handle for DrawPicture}°dONLNd5+<6»*
  8022.       longCount   : LONGINT;°dONLNdS5<@»*
  8023.       myEOF       : LONGINT;°dONLNdq?<J»*
  8024.       myFilePos   : LONGINT;°dONLNdèS<^d*   BEGIN°dONLNdô]<hõ*
  8025.       wher.h := 20;°dONLNdÆg<rõ*
  8026.       wher.v := 20;°dONLNd√q<|;*
  8027. 3      numFileTypes := 1;       {display PICT files}°dONLNd¯{<Ü◊*
  8028.       myFileTypes[0] := 'PICT';°dONLNdÖ<ê|*
  8029. @      SFGetFile(wher,'',NIL,numFileTypes,myFileTypes,NIL,reply);°dONLNd[ô<§“*      IF reply.good THEN BEGIN°dONLNd{£<ÆÅ*
  8030. A         SetStdProcs(myProcs); {use SetStdCProcs for a CGrafPort}°dONLNdæ≠<∏*
  8031. ,         myProcs.getPicProc := @GetPICTData;°dONLNdÏ∑<¬ö*
  8032. F         savedProcs := thePort^.grafProcs; {set the grafProcs to ours}°dONLNd4¡<Ã*
  8033. (         thePort^.grafProcs := @myProcs;°dONLNd^’<‡r*>         myPicture := PicHandle(NewHandle(SizeOf(myPicture)));°dONLNdûÈ<Ùm*=         Signal(FSOpen(reply.fname,reply.vRefNum,globalRef));°dONLNd›Û<˛ã*
  8034. C         Signal(GetEOF(globalRef,myEOF)); {get EOF for later check}°dONLNd"˝<Ü*
  8035. B         Signal(SetFPos(globalRef,fsFromStart,512)); {skip header}°dONLNdf<h*<         {read in the (obsolete) size word and the picFrame}°dONLNd§<&*
  8036. (         longCount := SizeOf(myPicture);°dONLNdŒ%<0m*
  8037. =         Signal(FSRead(globalRef,longCount,Ptr(myPicture^)));°dONLNd
  8038. 9<D§*H         DrawPicture(myPicture,myPicture^^.picFrame); {draw the picture}°dONLNdWM<Xï*E         Signal(GetFPos(globalRef,filePos)); {get position for check}°dONLNdûW<b*
  8039. $         Signal(FSClose(globalRef));°dONLNdƒk<v    *)         DisposHandle(Handle(myPicture));°dONLNdÔ<är*>         thePort^.grafProcs := savedProcs; {restore the procs}°dONLNd/ì<ûY*9         {Check for errors. If there wasn't enough room,}°dONLNdjù<®Y*
  8040. 9         {DrawPicture will abort; the FILE position mark} ◊4◊˘
  8041. (Ï62) of 5(Ï≤Large PICT Filesˇ \◊#ˇ ˇˇˇˇ#◊ 
  8042. IR,Times
  8043. .+Z-Developer Support Center(-Ï
  8044. March 1988 /X/,
  8045. Courier
  8046.     °dONLNd`(7(D~+         {won't be at the end of the FILE.}°dONLNd-'`2d*
  8047. 4         IF filePos <> myEOF THEN Signal(abortPICT);°dONLNdc1`<‚*
  8048.       END; {IF reply.good}°dONLNd;`F›*
  8049.    END; {GetDrawPICTFile}
  8050. °dONLNdô]<l≠(àZ
  8051. MPW C Example
  8052.     °dONLNdßx<É@*4/*replacement for the QuickDraw bottleneck routine*/°dONLNd‹Ç<ç*
  8053. *pascal void GetPICTData(dataPtr,byteCount)°dONLNdå<óK*
  8054. Ptr°dONLNd
  8055. å®ó–)ldataPtr;°dONLNdñ<°U(ΩZshort°dONLNdñ®°⁄)l
  8056. byteCount;°dONLNd*¥<øõ(€Z{ /* GetPICTData */°dONLNd?æ`…y+$
  8057. OSErr°dONLNdGæÃ…‡)lerr;°dONLNdM»`”t(Ô~long°dONLNdT»Ã”˛)l
  8058. longCount;°dONLNd`‹`ÁŒ(~longCount = byteCount;°dONLNdxÊ`Ò7*
  8059. +err = FSRead(globalRef,&longCount,dataPtr);°dONLNd•`˚Ø*
  8060. C/*can't check for an error because we don't know how to handle it*/°dONLNdÈ˙<õ(!Z} /* GetPICTData */°dONLNd˝<ı*%/*error code if DrawPicture aborted*/°dONLNd#<#_*
  8061. #define°dONLNd+Ñ#Ë)H   abortPICT     128°dONLNdI,<7Ø(SZOSErr GetDrawPICTFile()°dONLNdb,7Ã)¥,/*read in a PICT FILE selected by the user*/°dONLNdè@<KA(gZ{°dONLNdë@`K…)$/* GetDrawPICTFile */°dONLNd´T`_~*Point °dONLNd≥T®_Δ)Hwher; °dONLNdªT_w)H/*where to display dialog*/°dONLNdÿ^`iÉ(Ö~SFReply°dONLNd‡^®i–)Hreply;  °dONLNdÈ^i@)H/*reply record*/°dONLNd˚h`sí(è~
  8062. SFTypeList°dONLNdh®s‰)H myFileTypes;°dONLNdhsÜ)H/*more Standard FILE goodies*/°dONLNd3r`}~(ô~short °dONLNd;r®}È)H
  8063. numFileTypes;°dONLNdJ|`áy(£~OSErr°dONLNdQ|®áº)Herr;°dONLNdWÜ`ëí(≠~
  8064. QDProcsPtr°dONLNdbÜ®ëfl)H savedProcs;°dONLNdoê`õÉ(∑~QDProcs°dONLNdwê®õ–)HmyProcs;°dONLNdÄêõü)H#/*use CQDProcs for a color window*/°dONLNd•ö`•ç(¡~    PicHandle°dONLNdØö®•⁄)H
  8065. myPicture;°dONLNd∫ö•Ã)H,/*we need a picture handle for DrawPicture*/°dONLNd˧`Øt(À~long°dONLNdÓ§®Ø )HlongCount,myEOF,filePos;°dONLNd∏`√∫(fl~      wher.h = 20;°dONLNd¬`Õ∫*
  8066.       wher.v = 20;°dONLNd0Ã`◊ˆ*
  8067.       numFileTypes = 1;       °dONLNdQÃ\◊ )¸/*display PICT files*/°dONLNdi÷`·ˆ(˝~      myFileTypes[0] = 'PICT';°dONLNdâ‡`Ε*
  8068. A      SFGetFile(wher,'',nil,numFileTypes,myFileTypes,nil,&reply); ◊X◊
  8069. (ÏZLarge PICT Files(Ï3) of 5ˇt◊#ˇ ˇˇˇˇ#◊ 
  8070. IR,Times
  8071. .+6-Macintosh Technical Notes /4/˘,
  8072. Courier
  8073.     °dONLNd'<2•+$!      if (reply.good)°dONLNd1`<e+$
  8074. {°dONLNd;ÑFÚ+$
  8075. SetStdProcs(&myProcs);°dONLNd9EÑP8*
  8076. $/*use SetStdCProcs for a CGrafPort*/°dONLNd_O<Zi(vZ             °dONLNdiOÑZ))H!myProcs.getPicProc = GetPICTData;°dONLNdåY<di(ÄZ             °dONLNdñYÑd=)H%savedProcs = (*qd.thePort).grafProcs;°dONLNdømÑx*/*set the grafProcs to ours*/°dONLNdfiw<Çi(ûZ             °dONLNdËwÑÇ3)H#(*qd.thePort).grafProcs = &myProcs;°dONLNd
  8077. ã<ñi(≤Z             °dONLNdãÑñ~)H2myPicture = (PicHandle)NewHandle(sizeof(Picture));°dONLNdMüÑ™à*4err = FSOpen(&reply.fName,reply.vRefNum,&globalRef);°dONLNdÖ©Ñ¥*
  8078. if (err != noErr) return err;°dONLNd§Ω<»U(‰Z     °dONLNd™Ω`»e)$ °dONLNd¨ΩÑ»)$err = GetEOF(globalRef,&myEOF);°dONLNdœ«Ñ“ *
  8079. /*get EOF for later check*/°dONLNdÓ—Ñ‹*
  8080. if (err != noErr) return err;°dONLNdÂÑú*8err = SetFPos(globalRef,fsFromStart,512);/*skip header*/°dONLNdIÔ<˙i(Z             °dONLNdSÔÑ˙)Hif (err != noErr) return err;°dONLNdr<i(*Z             °dONLNd|Ñç)H5/*read in the (obsolete) size word and the picFrame*/°dONLNd≥
  8081. <i(4Z             °dONLNdΩ
  8082. Ñ)HlongCount = sizeof(Picture);°dONLNd€<"d(>Z        °dONLNd‰Ñ"à)H4 err = FSRead(globalRef,&longCount,(Ptr)*myPicture);°dONLNd!<,i(HZ             °dONLNd$!Ñ,)Hif (err != noErr) return err;°dONLNdC5<@i(\Z             °dONLNdM5Ñ@ó)H7DrawPicture(myPicture,&(**myPicture).picFrame); /*draw °dONLNdå?JU+ê
  8083.  
  8084. the picture*/°dONLNdùSÑ^ç(z¢5err = GetFPos(globalRef,&filePos);/*get position for °dONLNd⁄]h7+ê
  8085. check*/°dONLNd„g<ri(éZ             °dONLNdÌgÑr)Hif (err != noErr) return err;°dONLNd q<|i(òZ             °dONLNdqÑ|)Herr = FSClose(globalRef);°dONLNd1{<Üi(¢Z             °dONLNd;{ÑÜ)Hif (err != noErr) return err;°dONLNdZè<öi(∂Z             °dONLNddèÑö$)H DisposHandle((Handle)myPicture);°dONLNdÜ£<Æi( Z             °dONLNdê£ÑÆÉ)H3(*qd.thePort).grafProcs = savedProcs;/*restore the °dONLNdÀ≠∏7+ê
  8086. procs*/°dONLNd‘¡<Ãd(ËZ        °dONLNd›¡ÑÃÉ)H3 /*Check for errors. if there wasn't enough room,*/°dONLNdÀ<÷d(ÚZ        °dONLNdÀÑ÷É)H3 /*DrawPicture will abort; the FILE position mark*/°dONLNdP’<‡i(¸Z             °dONLNdZ’ч8)H$/*won't be at the end of the FILE.*/°dONLNdÇÈÑÙL*(if (filePos != myEOF)  return abortPICT;°dONLNdÆÛÑ˛fi*
  8087. else return noErr;°dONLNd¬˝<»($Z      } /*if (reply.good) */°dONLNdfl"(.6} °dONLNd‚<•)$/* GetDrawPICTFile */
  8088. °dONLNd¯)8Â(T6More on Picture Compatibility
  8089. °dONLNdDPô*Many applications already °dONLNd0DôP⁄)Å:support PICT resources larger than 32K. The 128K ROMs (and°dONLNdkP\‰(x6)later) allow pictures as large as memory °dONLNdîP‰\⁄)Ã-(or spooling) will accommodate. This was made°dONLNd¬\hŒ(Ñ6$possible by having QuickDraw ignore °dONLNdÊ\Œh÷)∂7the size word and simply read the picture until the end°dONLNd\÷h⁄(ÑÙ-°dONLNdht¨(ê6of-picture opcode was reached.°dONLNd=Äå√*WFor maximum safety and convenience, let QuickDraw generate and interpret your pictures. ◊4◊˘
  8090. *D4) of 5(Ï≤Large PICT Filesˇ ◊#ˇ ˇˇˇˇ#◊ 
  8091. IR,Times
  8092. .+Z-Developer Support Center(-Ï
  8093. March 1988 /X/
  8094. °dONLNd<)´(EZMWhile Apple has provided you with the data formats that allow you to read or °dONLNdM´)˛(E…write picture data°dONLNd`)<5(QZ+directly, we recommend that you always let °dONLNdã)5˛)fi+DrawPicture or OpenPicture and ClosePicture°dONLNd∑5<Aü(]Zprocess the opcodes.°dONLNdÃM<Yfl*YOne reason to read a picture directly by scanning the opcodes would be to disassemble it °dONLNd%MflY˛(u˝to, for°dONLNd-Y<eó(ÅZexample, extract a °dONLNd@Yóe˛)[GColor QuickDraw pixel map to save off in a private data structure. This°dONLNdàe<qŸ(çZ shouldn’t normally be necessary.°dONLNd©}<âÊ*&If you do look at the picture data be °dONLNdœ}Êâ˛)™7sure and check the version information. You may want to°dONLNdâ<ï(±Z3put up an alert in your application that indicates °dONLNd:âï˛)·.to the user when a picture was created using a°dONLNdiï<°Ì(ΩZXlater version of the picture format than your application recognizes, letting them know °dONLNd¡ḭ̈˛(Ω that°dONLNdΔ°<≠…(…ZMsome elements of the picture cannot be displayed. If the version information °dONLNd°…≠˛(…Á indicates a°dONLNd≠<πŸ(’Z QuickDraw picture version later °dONLNd?≠Ÿπ˛)ù9than the one recognized by your application, your program°dONLNdyπ<≈∞(·ZMshould skip over the new opcodes and only attempt to parse the ones it knows.°dONLNd«—<›-*5As with reading picture data directly, it is best to °dONLNd¸—-›˛)Ò(use QuickDraw to create data in the PICT°dONLNd%›<ÈS(Z<format. If you do need to create PICT format data directly, °dONLNda›SÈ˛(q'it is essential that you use the latest°dONLNdâÈ<ıÂ(ZWopcode specifications and that you thoroughly test the data produced on both color and °dONLNd‡ÈÂı˛(black°dONLNdÊı<í(ZDand white Macintosh machines. Contact Macintosh Developer Technical °dONLNd*ıí˛(∞Support if you are not°dONLNdA<
  8095. ()Z-sure that you have the latest specifications.°dONLNdo<%·*UApple does not guarantee that a picture which wasn’t produced by QuickDraw will work.°dONLNd≈I<U¶*0Further Reference: tXt°dONLNdÿVNbR+
  8096. •°dONLNd⁄V`bñ)    QuickDraw°dONLNd‰bNnR(äl•°dONLNdÊb`n#)$Technical Note M.IM.PictureOpcodes —°dONLNd
  8097. nÑzÒ+$ Internal Picture Format°dONLNd%zNÜR(¢l•°dONLNd'z`ܸ)Technical Note M.PT.Signals —°dONLNdGÜÑíß+$ Signals ◊X◊
  8098. (ÏZLarge PICT Files(Ï5) of 5ˇ˙◊#ˇ ˇˇˇˇ#◊†Ç 
  8099. /ZÅ#
  8100.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8101. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8102. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8103. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8104. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8105.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8106. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8107. IR.°dONLNdn<Å(õZLaserWriter Utility Q&As
  8108. °dONLNdÄ<èr*Imaging°dONLNd!Äuè˛(´ìM.IM.LWUtil.Q&As
  8109. °dONLNd2õ<ßt(√Z Revised by:°dONLNd>õÑߡ)HDeveloper Support Center°dONLNdWõæß˛(√‹ October 1992°dONLNddß<≥q(œZ Written by:°dONLNdpßÑ≥ˇ)HDeveloper Support Center°dONLNdâßæ≥˛(œ‹ October 1990°dONLNdñø<À⁄(ÁZThis Technical Note contains a °dONLNdµø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÔÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd6À†◊˛(Ûæthe DSC engineers.°dONLNdI◊<„u(ˇZ
  8110. While DSC °dONLNdS◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNd†„<Ôq( Z don’t have °dONLNd´„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˝Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdR˚<(#Z,information migrates into reference manuals.°dONLNd<k*:Q&As are now included with Technical Notes to make access °dONLNdπk˛(;âto technical updates easier for°dONLNdŸ<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd3+<7\(SZknow °dONLNd8+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNdÇ7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdºO<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  8111. °dONLNd Ä<è‹*49SCSI drive format for LaserWriter II NTX with Rev. 3 ROMs
  8112. °dONLNdEè<õb* Written:°dONLNdNèàõ¶)L5/3/91°dONLNdUõ<ßÅ(√ZLast reviewed:°dONLNddõàߨ)L6/26/91°dONLNdl≥<øW(€Z<What could be causing intermittent PostScript errors from a °dONLNd®≥Wø˛(€uLaserWriter II NTX with an SCSI°dONLNd»ø<ÀU(ÁZ9hard disk mounted after installing the Rev 3 ROM upgrade?°dONLNdÀ<◊N* ___°dONLNd„<Ô~*>The LaserWriter II NTX with Rev 3 ROMs does not work properly °dONLNdD„~Ô˛( úwith a hard disk formatted°dONLNd_Ô<˚e(Z    with the °dONLNdhÔe˚˛))SLaserWriter Font Utility 1.x. You need to reformat the disk and copy the fonts back°dONLNdº˚<¬(#Zonto the hard disk using the °dONLNdŸ˚¬˛)ÜALaserWriter Font Utility 2.0.2. Unfortunately, there is no way to°dONLNd<Ω(/Zmake this procedure easier.
  8113. °dONLNd7+<:π*':LaserWriter Font Utility copies Postscript file to printer
  8114. °dONLNdr:<Fb* Written:°dONLNd{:àF¨)L9/23/91°dONLNdÉF<RÅ(nZLast reviewed:°dONLNdíFàR¨)L10/8/91°dONLNdö^<j£(ÜZQIs there a utility that will send a PostScript file from disk to the LaserWriter?°dONLNdÏj<vN* ___°dONLNdÇ<éé*The LaserWriter °dONLNdÇéé˛)RJFont Utility handles this job and is part of the System 7 disk set. On the°dONLNdKé<öÀ(∂ZSystem 7 Golden Master CD, °dONLNdféÀö˛)è?the path is System 7.0: System Software 7.0: Installer Version:°dONLNd¶ö<¶Ä(¬ZTidbits folder. ◊X◊
  8115. **LaserWriter Font Utility Q&As(Ï1) of 1ˇ°¿Ù%%DSIDICT:_cv
  8116. currentdict /bu known {bu}if
  8117. userdict /_cv known not{userdict /_cv 30 dict put}if
  8118. _cv begin
  8119. /bdf{bind def}bind def
  8120. currentscreen/cs exch def/ca exch def/cf exch def
  8121. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8122. /ss{//cf //ca //cs setscreen}bdf
  8123. /stg{ss setgray}bdf
  8124. /strgb{ss setrgbcolor}bdf
  8125. /stcmyk{ss cvcmyk}bdf
  8126. /min1{dup 0 eq{pop 1}if}bdf
  8127. end
  8128. currentdict /bn known {bn}if
  8129. †øT◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  8130. /ZÅ#
  8131.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8132. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8133. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8134. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8135. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8136.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8137. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  8138. IR.°dONLNdo<Çc(úZ!Drawing Into an Off-Screen Bitmap
  8139. °dONLNd"Å<êr*Imaging°dONLNd*Åcê˛(¨ÅM.IM.OffscreenBitMap
  8140. °dONLNd?ú<®t(ƒZ Revised by:°dONLNdKúÑ®)HJon Zap & Forrest Tanaka°dONLNddúÕ®˛(ƒΠ   June 1990°dONLNdn®<¥q(–Z Written by:°dONLNdz®Ñ¥))H!Jim Friedlander & Ginger Jernigan°dONLNdú®œ¥˛(–Ì    July 1985°dONLNd¶¿<Ãû(ËZThis Technical Note °dONLNd∫¿ûÃ˛)bHprovides an example of creating an off-screen bitmap, drawing to it, and°dONLNdÃ<ÿfi(ÙZ#then copying from it to the screen.°dONLNd'ÿ<‰ÿ* Changes since April 1990:°dONLNd@ÿÿ‰#)ú  Clarified the °dONLNdPÿ#‰˛)K)section on window updates with off-screen°dONLNdz‰<e( Z>bitmaps to explicitly limit these updates to your own windows. X°dONLNdπ    <*%(The following is an example of creating °dONLNd·    ˛)≈1and drawing to an off-screen bitmap, then copying°dONLNd<!”(=ZQfrom it to an on-screen window.  We supply this example in both MPW Pascal and C.°dONLNde-<9É*
  8141. MPW Pascal°dONLNdpE<Q*'First, let’s look at a general purpose °dONLNdóEQ˛)¥7function to create an off-screen bitmap.  This function°dONLNdœR<^t(zZ creates the ,
  8142. Courier°dONLNd€Qt]¨)8GrafPort°dONLNd„R¨^Ù)8 on the heap. °dONLNdÒRÙ^˛)H3 You could also create it on the stack and pass the°dONLNd%^<j:(ÜZ:uninitialized structure to a function similar to this one.
  8143.     °dONLNd`v<Å÷*RFUNCTION CreateOffscreenBitMap(VAR newOffscreen:GrafPtr; inBounds:Rect) : BOOLEAN;°dONLNd≥ä<ïK*VAR°dONLNd∑î<ü™*
  8144.   savePort  : GrafPtr;°dONLNdŒû<©™*
  8145.   newPort   : GrafPtr;°dONLNdÂ≤<ΩU*BEGIN°dONLNdκ<«‡*
  8146. T  GetPort(savePort);        {need this to restore thePort after OpenPort changes it}°dONLNd@–<€Æ*J  newPort := GrafPtr(NewPtr(sizeof(GrafPort)));    {allocate the GrafPort}°dONLNdã⁄<·*
  8147. !  IF MemError <> noErr THEN BEGIN°dONLNd≠‰<ÔÆ*
  8148. J    CreateOffscreenBitMap := false;                {failed to allocate it}°dONLNd¯Ó<˘‹*
  8149.      EXIT(CreateOffscreenBitMap);°dONLNd¯<Z*
  8150.   END;°dONLNd <
  8151. K*
  8152.   {°dONLNd$ <*
  8153. ,  the OpenPort call does the following . . .°dONLNdR<!«*
  8154. O    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide°dONLNd¢ <+U*
  8155. open)°dONLNd®*<5◊*
  8156.     sets portBits to screenBits°dONLNd»4<?˙*
  8157. &    sets portRect to screenBits.bounds°dONLNdÔ><I√*
  8158.     etc. (see IM I-163,164)°dONLNd H<S*
  8159. *    side effect: does a SetPort(offScreen)°dONLNd6R<]K*
  8160.   }°dONLNd:\<g†*
  8161.   OpenPort(newPort);°dONLNdOf<qã*
  8162. C  {make bitmap exactly the size of the bounds that caller supplied}°dONLNdìp<{ü*
  8163. G  WITH newPort^ DO BEGIN {portRect, clipRgn, and visRgn are in newPort}°dONLNd€z<Öπ*
  8164.     portRect := inBounds;°dONLNdıÑ<è∏*
  8165. L    RectRgn(clipRgn, inBounds);        {avoid wide-open clipRgn, to be safe}°dONLNdBé<ô∏*
  8166. L    RectRgn(visRgn, inBounds);         {in case inBounds is > screen bounds}°dONLNdèò<£Z*
  8167.   END; ◊X◊
  8168. *-!Drawing Into an Off-Screen Bitmap(Ï1) of 6ˇ°¿Ù%%DSIDICT:_cv
  8169. currentdict /bu known {bu}if
  8170. userdict /_cv known not{userdict /_cv 30 dict put}if
  8171. _cv begin
  8172. /bdf{bind def}bind def
  8173. currentscreen/cs exch def/ca exch def/cf exch def
  8174. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8175. /ss{//cf //ca //cs setscreen}bdf
  8176. /stg{ss setgray}bdf
  8177. /strgb{ss setrgbcolor}bdf
  8178. /stcmyk{ss cvcmyk}bdf
  8179. /min1{dup 0 eq{pop 1}if}bdf
  8180. end
  8181. currentdict /bn known {bn}if
  8182. †ø÷◊#ˇ ˇˇˇˇ#◊ 
  8183. IR,Times
  8184. .+6-Macintosh Technical Notes /4/˘,
  8185. Courier
  8186.     °dONLNd(ô*M  WITH newPort^.portBits DO BEGIN       {baseAddr, rowBytes and bounds are in°dONLNdN'2@*
  8187. newPort}°dONLNdW1<ã*
  8188.     bounds := inBounds;°dONLNdo;Fî*
  8189. L    {rowBytes is size of row  It must be rounded up to even number of bytes}°dONLNdºEPg*
  8190. C    rowBytes := ((inBounds.right - inBounds.left + 15) DIV 16) * 2;°dONLNdYdD*<    {number of bytes in BitMap is rowBytes * number of rows}°dONLNd=cn≤*
  8191. R    {see note at end of Technical Note about using _NewHandle rather than _NewPtr}°dONLNdêmxè*
  8192. K    baseAddr := NewPtr(rowBytes * LONGINT(inBounds.bottom - inBounds.top));°dONLNd‹wÇ6*
  8193.   END;°dONLNd„Ååô*
  8194. M  IF MemError <> noErr THEN BEGIN    {see if we had enough room for the bits}°dONLNd1ãñÜ*
  8195.     SetPort(savePort);°dONLNdHï†l*
  8196. D    ClosePort(newPort);              { dump the visRgn and clipRgn }°dONLNdçü™5*
  8197. 9    DisposPtr(Ptr(newPort));         { dump the GrafPort}°dONLNd«©¥«*
  8198. #    CreateOffscreenBitMap := false;°dONLNdÎ≥æ1*
  8199.   END°dONLNdÒΩ»T*
  8200.   ELSE BEGIN°dONLNd˛«“Ä*
  8201. H    { since the bits are just memory, let's erase them before we start }°dONLNdG—‹q*
  8202. E    EraseRect(inBounds);            {OpenPort did a SetPort(newPort)}°dONLNdç€ʧ*
  8203.     newOffscreen := newPort;°dONLNd™ÂÜ*
  8204.     SetPort(savePort);°dONLNd¡Ô˙¬*
  8205. "    CreateOffscreenBitMap := true;°dONLNd‰˘6*
  8206.   END;°dONLNdÎ,*
  8207. END;
  8208. °dONLNd%∏*ZHere is the procedure to get rid of an off-screen bitmap created by the previous function:
  8209.     °dONLNdK1<5*9PROCEDURE DestroyOffscreenBitMap(oldOffscreen : GrafPtr);°dONLNdÖ;F1*
  8210. BEGIN°dONLNdãEP®*
  8211. P  ClosePort(oldOffscreen);                       { dump the visRgn and clipRgn }°dONLNd‹OZb*
  8212. B  DisposPtr(oldOffscreen^.portBits.baseAddr);    { dump the bits }°dONLNdYdb*
  8213. B  DisposPtr(Ptr(oldOffscreen));                  { dump the port }°dONLNdbcn,*
  8214. END;
  8215. °dONLNdgyÖè*HNow that you know how to create and destroy an off-screen bitmap, let’s °dONLNdØyèÖ⁄(°≠go through the°dONLNdæÜí^(Æ6Dmotions of using one.  First, let’s define a few things to make the °dONLNdÖ^ë§(Æ|
  8216. _NewWindow°dONLNd ܧíº)F call °dONLNdܺí⁄)a little°dONLNdíû;(∫6clearer.
  8217.     °dONLNd$™µ1*CONST°dONLNd*¥øÜ*
  8218.   kIsVisible   = true;°dONLNdAæ…ã*
  8219.   kNoGoAway    = false;°dONLNdY»”ê*
  8220.   kMakeFrontWindow = -1;°dONLNdr“›*
  8221. 0  myString     = 'The EYE';  {string to display}
  8222. °dONLNd£ËÙ±*!Here’s the body of the test code:
  8223.     °dONLNd≈ '*VAR°dONLNd…
  8224. 
  8225. *
  8226. 1  offscreen : GrafPtr;    {our off-screen bitmap}°dONLNd˚*
  8227. 4  ovalRect  : Rect;       {used for example drawing}°dONLNd0)*
  8228. /  myWBounds : Rect;       {for creating window}°dONLNd`(3q*
  8229. E  OSRect    : Rect;       {portRect and bounds for off-screen bitmap}°dONLNd¶2=ê*
  8230.   myWindow  : WindowPtr;°dONLNdøFQ1*BEGIN°dONLNd≈P[b*
  8231. B  InitToolbox;                       {exercise left to the reader}°dONLNddoD*<  myWBounds := screenBits.bounds;    { size of main screen }°dONLNdEny?*
  8232. ;  InsetRect(myWBounds, 50,50);       { make it fit better }°dONLNdÅxÉb*
  8233. B  myWindow := NewWindow(NIL, myWBounds, 'Test Window', kIsVisible,°dONLNdƒÇç≤*
  8234. R                        noGrowDocProc, WindowPtr(kMakeFrontWindow), kNoGoAway, 0); ◊4◊˘
  8235. *C2) of 6(Ïj!Drawing Into an Off-Screen BitmapˇÏ◊#ˇ ˇˇˇˇ#◊ 
  8236. IR,Times
  8237. .+Z-Developer Support Center(-Û    June 1990 /X/,
  8238. Courier
  8239.     °dONLNd'<2ü(NZG  IF NOT CreateOffscreenBitMap(offscreen,myWindow^.portRect) THEN BEGIN°dONLNdI1<<á*
  8240.     SysBeep(1);°dONLNdY;<Få*
  8241.     ExitToShell;°dONLNdjE<PZ*
  8242.   END;°dONLNdqY<d"*.  { Example drawing to our off-screen bitmap }°dONLNd†c<n•*
  8243.   SetPort(offscreen);°dONLNd∂m<xÃ*
  8244. P  OSRect := offscreen^.portRect;    { offscreen bitmap's local coordinate rect }°dONLNdw<Ç•*
  8245.   ovalRect := OSRect;°dONLNdÅ<å»*
  8246.   FillOval(ovalRect, black);°dONLNd:ã<ñÕ*
  8247.   InsetRect(ovalRect, 1, 20);°dONLNdXï<†»*
  8248.   FillOval(ovalRect, white);°dONLNduü<™Õ*
  8249.   InsetRect(ovalRect, 40, 1);°dONLNdì©<¥»*
  8250.   FillOval(ovalRect, black);°dONLNd∞≥<æñ*
  8251.   WITH ovalRect DO°dONLNd√Ω<»∏*
  8252. L    MoveTo((left+right-StringWidth(myString)) DIV 2, (top+bottom-12) DIV 2);°dONLNd«<“õ*
  8253.   TextMode(srcXor);°dONLNd$—<‹Ø*
  8254.   DrawString(myString);°dONLNd<Â<«*O  { copy from the off-screen bitmap to the on-screen window.  Note that in this°dONLNdåÔ<˙∏*
  8255. L  case the source and destination rects are the same size and both cover the°dONLNdŸ˘<≥*
  8256. K  entire area.  These rects are allowed to be portions of the source and/or°dONLNd%<—*
  8257. Q  destination and do not have to be the same size.  If they are not the same size°dONLNdw
  8258. <*
  8259. -  then _CopyBits scales the image accordingly°dONLNd•<"K*
  8260.   }°dONLNd©!<,†*
  8261.   SetPort(myWindow);°dONLNdæ+<6;*
  8262. 3  CopyBits(offscreen^.portBits, myWindow^.portBits,°dONLNdÚ5<@Ü*
  8263. B           offscreen^.portRect, myWindow^.portRect, srcCopy, NIL);°dONLNd5I<Tm*=  DestroyOffscreenBitMap(offscreen);    {remove the evidence}°dONLNds]<h«*O  WHILE NOT Button DO;                  {give user a chance to see the results}°dONLNd√g<rP*
  8264. END.
  8265. °dONLNd»}<âh*MPW C°dONLNdŒï<°*'First, let’s look at a general purpose °dONLNdıï°˛)¥7function to create an off-screen bitmap.  This function°dONLNd-¢<Æt( Z creates the °dONLNd9°t≠¨)8GrafPort°dONLNdA¢¨ÆÙ)8 on the heap. °dONLNdO¢ÙÆ˛)H3 You could also create it on the stack and pass the°dONLNdÉÆ<∫:(÷Z:uninitialized structure to a function similar to this one.
  8266.     °dONLNdæΔ<—ê*DBoolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)°dONLNd–<€A*
  8267. {°dONLNd⁄<Âõ*
  8268.   GrafPtr savePort;°dONLNd‰<Ôñ*
  8269.   GrafPtr newPort;°dONLNd,¯<Æ*J  GetPort(&savePort);    /* need this to restore thePort after OpenPort */°dONLNdw <¬*N  newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */°dONLNdΔ<!æ*
  8270.   if (MemError() != noErr)°dONLNd· <+¬*
  8271. N    return false;                 /* failed to allocate the off-screen port */°dONLNd0*<5P*
  8272.   /*°dONLNd54<?'*
  8273. /  the call to OpenPort does the following . . .°dONLNdf><I«*
  8274. O    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide°dONLNd∂H<SU*
  8275. open)°dONLNdºR<]◊*
  8276.     sets portBits to screenBits°dONLNd‹\<g˙*
  8277. &    sets portRect to screenBits.bounds°dONLNdf<q√*
  8278.     etc. (see IM I-163,164)°dONLNdp<{*
  8279. +    side effect: does a SetPort(&offScreen)°dONLNdKz<ÖP*
  8280.   */°dONLNdPÑ<è†*
  8281.   OpenPort(newPort);°dONLNdeé<ôw*
  8282. ?  /* make bitmap the size of the bounds that caller supplied */°dONLNd•ò<£‹*
  8283.    newPort->portRect = *inBounds;°dONLNdΔ¢<≠ˇ*
  8284. '  newPort->portBits.bounds = *inBounds; ◊X◊
  8285. *#!Drawing Into an Off-Screen Bitmap(Ï3) of 6ˇd◊#ˇ ˇˇˇˇ#◊ 
  8286. IR,Times
  8287. .+6-Macintosh Technical Notes /4/˘,
  8288. Courier
  8289.     °dONLNd(º*T  RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */°dONLNdU'2º*
  8290. T  RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */°dONLNd™;F≠*Q  /* rowBytes is size of row, it must be rounded up to an even number of bytes */°dONLNd¸EP∑*
  8291. S  newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;°dONLNdPYdN*>  /* number of bytes in BitMap is rowBytes * number of rows */°dONLNdècn≤*
  8292. R  /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr°dONLNd‚mx"*
  8293. */°dONLNdÂwÇÆ*
  8294.   newPort->portBits.baseAddr =°dONLNdÅå≤*
  8295. R           NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds°dONLNdVÅ≤å∑(®–-°dONLNdWãñ;(≤6>top));°dONLNd_ï†≤*
  8296. R  if (MemError()!=noErr) {   /* check to see if we had enough room for the bits */°dONLNd≤ü™Ü*
  8297.     SetPort(savePort);°dONLNd…©¥N*
  8298. >    ClosePort(newPort);      /* dump the visRgn and clipRgn */°dONLNd≥æ*
  8299. 4    DisposPtr((Ptr)newPort); /* dump the GrafPort */°dONLNd=Ω»0*
  8300. 8    return false;            /* tell caller we failed */°dONLNdv«“1*
  8301.     }°dONLNd|—‹Ä*
  8302. H  /* since the bits are just memory, let's clear them before we start */°dONLNd≈€Êô*
  8303. M  EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */°dONLNdÂö*
  8304.   *newOffscreen = newPort;°dONLNd.Ô˙|*
  8305.   SetPort(savePort);°dONLNdC˘D*
  8306. <  return true;               /* tell caller we succeeded! */°dONLNdÄ*
  8307. }
  8308. °dONLNdÇ%∞*YHere is the function to get rid of an off-screen bitmap created by the previous function:
  8309.     °dONLNd‹1<
  8310. *1void DestroyOffscreenBitMap(GrafPtr oldOffscreen)°dONLNd;F*
  8311. {°dONLNdEP≤*
  8312. R  ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */°dONLNdcOZl*
  8313. D  DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */°dONLNd®Ydl*
  8314. D  DisposPtr((Ptr)oldOffscreen);                  /* dump the port */°dONLNdÌcn*
  8315. }
  8316. °dONLNdÔyÖè*HNow that you know how to create and destroy an off-screen bitmap, let’s °dONLNd7yèÖ⁄(°≠go through the°dONLNdFÜí^(Æ6Dmotions of using one.  First, let’s define a few things to make the °dONLNdäÖ^ë§(Æ|
  8317. _NewWindow°dONLNdîܧíº)F call °dONLNdöܺí⁄)a little°dONLNd£íû;(∫6clearer.
  8318.     °dONLNd¨™µã*#define kIsVisible true°dONLNdƒ¥øã*
  8319. #define kNoGoAway false°dONLNd‹æ…ü*
  8320. #define kNoWindowStorage 0L°dONLNd¯»”÷*
  8321. &#define kFrontWindow ((WindowPtr) -1L)
  8322. °dONLNdfiͱ*!Here’s the body of the test code:
  8323.     °dONLNdAˆ6*main()°dONLNdH *
  8324. {°dONLNdJ
  8325. 0*
  8326. 8  char* myString = "\pThe EYE";  /* string to display */°dONLNdÉ)D*<  GrafPtr   offscreen;           /* our off-screen bitmap */°dONLNd¿(3S*
  8327. ?  Rect      ovalRect;            /* used for example drawing */°dONLNd2=:*
  8328. :  Rect      myWBounds;           /* for creating window */°dONLNd;<G£*
  8329. O  Rect      OSRect;              /* portRect and bounds for off-screen bitmap*/°dONLNdãFQÅ*
  8330.   WindowPtr myWindow;°dONLNd°ZeN*>  InitToolbox();                 /* exercise for the reader */°dONLNd‡doN*
  8331. >  myWBounds = qd.screenBits.bounds;  /* size of main screen */°dONLNd    ny5*
  8332. 9  InsetRect(&myWBounds, 50,50);  /* make it fit better */°dONLNd    YxÉ≠*
  8333. Q  myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window", kIsVisible,°dONLNd    ´Ççb*
  8334. B                       noGrowDocProc, kFrontWindow, kNoGoAway, 0);°dONLNd    ÓåóX*
  8335. @  if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {°dONLNd
  8336. /ñ°c*
  8337.     SysBeep(1);°dONLNd
  8338. ?†´r*
  8339.     ExitToShell(); ◊4◊˘
  8340. *%4) of 6(Ïj!Drawing Into an Off-Screen Bitmapˇ.◊#ˇ ˇˇˇˇ#◊ 
  8341. IR,Times
  8342. .+Z-Developer Support Center(-Û    June 1990 /X/,
  8343. Courier
  8344.     °dONLNd<(U(DZ    }°dONLNd'<2'*
  8345. /  /* Example drawing to our off-screen bitmap*/°dONLNd61<<•*
  8346.   SetPort(offscreen);°dONLNdL;<F«*
  8347. O  OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect */°dONLNdúE<P†*
  8348.   ovalRect = OSRect;°dONLNd±O<Z‹*
  8349.    FillOval(&ovalRect, qd.black);°dONLNd“Y<d“*
  8350.   InsetRect(&ovalRect, 1, 20);°dONLNdÒc<n‹*
  8351.    FillOval(&ovalRect, qd.white);°dONLNdm<x“*
  8352.   InsetRect(&ovalRect, 40, 1);°dONLNd1w<Ç‹*
  8353.    FillOval(&ovalRect, qd.black);°dONLNdRÅ<åü*
  8354. G  MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,°dONLNdöã<ñE*
  8355. 5         (ovalRect.top + ovalRect.bottom - 12) >> 1);°dONLNd–ï<†õ*
  8356.   TextMode(srcXor);°dONLNd‰ü<™Ø*
  8357.   DrawString(myString);°dONLNd¸≥<æÃ*P  /* copy from the off-screen bitmap to the on-screen window.  Note that in this°dONLNdMΩ<»∏*
  8358. L  case the source and destination rects are the same size and both cover the°dONLNdö«<“≥*
  8359. K  entire area.  These rects are allowed to be portions of the source and/or°dONLNdÊ—<‹—*
  8360. Q  destination and do not have to be the same size.  If they are not the same size°dONLNd8€<Ê"*
  8361. .  then _CopyBits scales the image accordingly.°dONLNdgÂ<P*
  8362.   */°dONLNdlÔ<˙†*
  8363.   SetPort(myWindow);°dONLNdÅ˘<O*
  8364. 7  CopyBits(&offscreen->portBits, &(*myWindow).portBits,°dONLNdπ<ï*
  8365. E           &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);°dONLNdˇ<"§*H  DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */°dONLNdH!<,§*
  8366. H  while (!Button());     /* give user a chance to see our work of art */°dONLNdë+<6A*
  8367. }
  8368. °dONLNdìM<\Ä*&Comments
  8369. °dONLNdúi<u‰*%In the example code, the bits of the °dONLNd¡h‰t)®BitMap°dONLNd«iu§)*! structure, which are pointed to °dONLNdËi§uΔ)ñby the °dONLNdÔhΔt˛)"baseAddr°dONLNd¯v<DZ(ûZfield, are allocated by a °dONLNdu±Å‚)u_NewPtr°dONLNdv‚Çå)1% call.  If your off-screen bitmap is °dONLNd>våDz)™close to the size of the°dONLNdWÇ<éS(™Z:screen, then the amount of memory needed for the bits can °dONLNdëÇSé˛(™q#be quite large (on the order of 20K°dONLNdµé<öE(∂Z8for the Macintosh SE or 128K for a large screen).  This °dONLNdÌéEö˛(∂c%is quite a lot of memory to lock down°dONLNdö<¶Í(¬Z'in your heap and it can easily lead to °dONLNd:öͶ˛)Æ9fragmentation if you intend to keep the off-screen bitmap°dONLNdt¶<≤⁄(ŒZXaround for any length of time.  One alternative that lessens this problem is to get the °dONLNdö⁄≤˛(Œ¯bits via°dONLNd’≤<æÇ(€Z
  8370. _NewHandle°dONLNdfl≥Çø•)F6 so the Memory Manager can move them when necessary.  °dONLNd≥•ø˛(€√To implement this°dONLNd'¿<â(ËZapproach, you need °dONLNd:¿¢Ãc)f%to keep the handle separate from the °dONLNd_øcÀõ)¡GrafPort°dONLNdg¿õÃ˛)8 (for example, in a°dONLNd{Õ<Ÿ|(ıZstructure that °dONLNdäÕ|Ÿ∂)@ combines a °dONLNdïÃ∂ÿÓ):GrafPort°dONLNdùÕÓŸ)8 and a °dONLNd§Ãÿ:)"Handle°dONLNd™Õ:Ÿ˛)*').  When you want to use the off-screen°dONLNd“⁄<Ê7(Z2bitmap you would then lock the handle and put the °dONLNd⁄7ÊΔ)˚dereferenced handle into the °dONLNd!ŸΔ²)èbaseAddr°dONLNd*Ê<Ú¢(ZLfield.  When you are not using the off-screen bitmap you can then unlock it.°dONLNdw˛<
  8371. Â*"This example does not demonstrate °dONLNdô˛Â
  8372. ˛)©9one of the more typical uses of off-screen bitmaps, which°dONLNd”
  8373. <W(2Zis to °dONLNdŸ
  8374. W˛)Opreserve the contents of windows so that after a temporary window or dialog box°dONLNd    )<"˘(>Z%obscures part of your windows and is °dONLNd    N˘"˛)Ω4then dismissed, you can quickly handle the resulting°dONLNd    É"<.†(JZJupdate events without recreating all of the intermediate drawing commands.°dONLNd    Œ:<Fz*DMake sure you only restore the pixels within the content regions of °dONLNd
  8375. :zF˛(bòyour own windows in case°dONLNd
  8376. +F<Rˇ(nZ%the temporary window partly obscures °dONLNd
  8377. PFˇR˛)√1windows belonging to other applications or to the°dONLNd
  8378. ÇR<^Á(zZ$desktop.  Another application could °dONLNd
  8379. ¶RÁ^˛)´8change the contents of its windows while they are behind°dONLNd
  8380. fl^<jt(ÜZ<your temporary window, so you cannot simply restore all the °dONLNd ^tj˛(Üípixels that were behind the°dONLNd 7j<vq(íZ
  8381. temporary °dONLNd Ajqv˛)5Mwindow because that would restore the old contents of the other application’s°dONLNd èv<Çõ(ûZwindows.  Instead, °dONLNd ¢võDz)_Eyou could keep keep an off-screen bitmap for each of your windows and°dONLNd ËÇ<év(™Z
  8382. then restore °dONLNd ıÇvé˛):Lthem by copying each bit map into the corresponding window’s ports when they°dONLNd Bé<ö©(∂Zget their update events. ◊X◊
  8383. *6!Drawing Into an Off-Screen Bitmap(Ï5) of 6ˇ"◊#ˇ ˇˇˇˇ#◊ 
  8384. IR,Times
  8385. .+6-Macintosh Technical Notes /4/˘
  8386. °dONLNd)|*An alternate method °dONLNd|)⁄)dGis to make a single off-screen bitmap that is as large as the temporary°dONLNd\)5û(Q6Nwindow and a region that is the union of the content regions of your windows. °dONLNd™)û5⁄(Qº  Before you°dONLNd∂5A(]63display the temporary window, copy the screen into °dONLNdÈ5A⁄)¯*the off-screen bit map using the region as°dONLNdAM
  8387. (i62a mask.  After the temporary window is dismissed, °dONLNdFA
  8388. M⁄)ı)restore the obscured area by copying from°dONLNdpMYI(u6?the off-screen bit map into a copy of the Window Manager port, °dONLNdØMIY⁄(ugand use the region as a mask.°dONLNdŒZf˘(Ç61If the region has the proper shape and location, °dONLNdˇZ˘f/)· it prevents ,
  8389. Courier°dONLNd Y/en)6    _CopyBits°dONLNdZnf⁄)? from drawing outside°dONLNd*frÌ(é6)of the content regions of your windows.  °dONLNdSfÌr⁄)’,See Technical Note #194, WMgrPortability for°dONLNdÄr~—(ö6%details about drawing across windows.°dONLNd¶äñy*In some cases it can °dONLNdªäyñ⁄)aIbe just as fast and convenient to simply define a picture (PICT) and then°dONLNdñ¢ú(æ6Ldraw it into your window when necessary.  There are cases, however, such as °dONLNdQñú¢⁄(æ∫text rotation,°dONLNd`¢ÆL( 6 where it is °dONLNdl¢LÆ⁄)4Qadvantageous to do the drawing off the screen, manipulate the bit image, and then°dONLNdæÆ∫…(÷6© the result to the visible window °dONLNd‰Æ…∫⁄)±:(thus avoiding the dangers inherent in writing directly to°dONLNd∫Δb(‚6Jthe screen).  In addition, this technique reduces flicker, because all of °dONLNdi∫bΔ⁄(‚Äthe drawing done off the°dONLNdÇΔ“Δ(Ó6%screen appears on the screen at once.°dONLNd®fiÍ&*;It is also important to realize that, if you plan on using °dONLNd„fi&Í⁄(D#the pre-Color QuickDraw eight-color°dONLNd͈}(6model, an off-screen °dONLNdÍ}ˆ⁄)eFbitmap loses any color information and you do not see your colors on a°dONLNdcˆÃ(6^system that is capable of displaying them.  In this case you should either use a PICT to save °dONLNd¡ˆÃ⁄(Íthe°dONLNd≈c(*6Adrawing information or check for the presence of Color QuickDraw °dONLNdc⁄(*Åand, when it is present,°dONLNd3(76use a °dONLNd%3])PixMap°dONLNd+]ô)* instead of a °dONLNd9ô√)<BitMap°dONLNd?√)* and the color °dONLNdNK)Ctoolbox calls (°dONLNd]Kù)EInside Macintosh°dONLNdmù⁄)R , Volume V)°dONLNdy'⁄(C6)instead of the standard QuickDraw calls (°dONLNd¢⁄'+)¬Inside Macintosh°dONLNd≤+'f)Q , Volume I).°dONLNdø3?\([6
  8390. You may also °dONLNdÃ3\?⁄)DKwant to refer to the OffScreen library (DTS Sample Code #15) which provides°dONLNd?KP(g6 both high- °dONLNd#?PK⁄)8Iand low-level off-screen bitmap support for the 128K and later ROMs.  The°dONLNdmKW•(s6QOffSample application (DTS Sample Code #16) demonstrates the use of this library.°dONLNdø{áÇ*0Further Reference: ¶4¶˘°dONLNd“à*î.+
  8391. •°dONLNd‘à<îç)Inside Macintosh°dONLNd‰àçî)Q, Volumes I & IV, QuickDraw°dONLNdî*†.(ºH•°dONLNdî<†ç)Inside Macintosh°dONLNdîç†)Q, Volume V, Color QuickDraw°dONLNd.†*¨.(»H•°dONLNd0†<¨
  8392. )(Technical Note M.IM.PrincipiaOffscreen —°dONLNd[¨`∏4+$ *Principia Off-Screen Graphics Environments°dONLNdÜ∏*ƒ.(‡H•°dONLNdà∏<ƒÈ)Technical Note M.TB.WMgrPort —°dONLNd©ƒ`–≥+$  WMgrPortability°dONLNd∫–*‹.(¯H•°dONLNdº–<‹o)9DTS Macintosh Sample Code #15, OffScreen & #16, OffSample ◊4◊˘
  8393. (Ï66) of 6(Ïj!Drawing Into an Off-Screen Bitmapˇº◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  8394. /ZÅ#
  8395.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8396. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8397. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8398. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8399. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8400.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8401. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  8402. IR.°dONLNd{<éΔ(®ZOld Style Colors
  8403. °dONLNdç<úr*Imaging°dONLNdçêú˛(∏ÆM.IM.OldColors
  8404. °dONLNd(®<¥t(–Z Revised by:°dONLNd4®Ñ¥)HRich “I See Colors” Collyer°dONLNdP®¡¥˛(–fl August 1990°dONLNd\¥<¿q(‹Z Written by:°dONLNdh¥Ñ¿L)H'Rich “I See Colors” Collyer & Byron Han°dONLNdê¥æ¿˛(‹‹ October 1989°dONLNdùÃ<ÿ
  8405. (ÙZ*This Technical Note covers limitations of °dONLNd«Ã
  8406. ÿ˛)—0the original Macintosh color model (eight-color)°dONLNd¯ÿ<‰\(Zwhich °dONLNd˛ÿ\‰≠) Inside Macintosh°dONLNdÿ≠‰ì)Q,, Volume I-173, QuickDraw does not document.°dONLNd;‰<·( ZChanges since October 1989:°dONLNdV‰·∏)•/  Added definitions of the old-style constants. X°dONLNdÜ    <Û(1Z"QuickDraw has always been able to °dONLNd®    Û˛)∑4deal with color, just on a very limited basis.  Most°dONLNd›<!)(=Z0applications have not made use of this feature, °dONLNd
  8407. )!˛)Ì'since Color QuickDraw-based Macintoshes°dONLNd5!<-:(IZ5come with a better color model.  There are, however, °dONLNdj!:-˛)˛'a few nice features which come with the°dONLNdí-<9\(UZ>old style color model.  With the old style colors, it is easy °dONLNd–-\9˛(Uz to print color on an ImageWriter°dONLNdÒ9<E#(aZ0with a color ribbon.  Another advantage is that °dONLNd!9#E˛)Á,developers do not have to write special-case°dONLNdNE<Qâ(mZAcode depending upon whether or not a machine has Color QuickDraw.°dONLNdê]<ié*GNow that you are ready to convert to the old style colors, there are a °dONLNd◊]éi˛(Ö¨few things you should°dONLNdÌi<u‰(ëZYknow about which do not work with old style colors.  This Note covers the limitations of °dONLNdFi‰u˛(ëusing°dONLNdLu<Åõ(ùZLold style colors, as well as the best ways to work around these limitations.
  8408. °dONLNdôô<®à*' Limitations
  8409. °dONLNd•¥<¿‚*$The most obvious limitation is that °dONLNd…¥‚¿˛)¶<of only eight colors:  black, white, red, green, blue, cyan,°dONLNd¿<Ã"(ËZ.yellow, and magenta.  This limitation is only °dONLNd4¿"Ã˙)Ê(a problem if you want to produce a color°dONLNd\¿˙Ã˛)ÿ-°dONLNd]Ã<ÿı(ÙZ^intensive application; if this describes your application, then you need not read any further °dONLNdªÃıÿ˛(Ùin°dONLNdæÿ<‰k(Z
  8410. this Note.°dONLNd…<¸p*EThe next limitation is that off-screen buffers are not very useful.  °dONLNdp¸˛(éYou can draw into off-screen°dONLNd+¸<£($ZKbuffers, but there is no way to get the colors back from the buffer.  This °dONLNdv¸£˛($¡leads into the next°dONLNdä    <Æ(1Zlimitation, which is that ,
  8411. Courier°dONLNd§ÆÌ)r    _CopyBits°dONLNd≠    Ì∏)?+ cannot copy more than one color at a time.°dONLNdŸ"<.Ü(JZWhen you call °dONLNdÁ!Ü-≈)J    _CopyBits°dONLNd"≈.û)?+ from an off-screen buffer to your window, °dONLNd"û.˛)Ÿyou need to set the°dONLNd//<;(WZ/forecolor to the color you want to copy before °dONLNd^/;;)‹calling °dONLNdf.;:z)#    _CopyBits°dONLNdo/z;˛)? (i.e., to copy a red object,°dONLNdç<<HP(dZcall °dONLNdí;PG‹)_ForeColor(redColor)°dONLNd¶<‹H∑)å*).  Now when you copy the object, you can °dONLNd–<∑H˛)€
  8412. only copy one°dONLNdfiH<T
  8413. (pZ.color.  If you copy different colored objects °dONLNd H
  8414. T˛)—1at one time, then you have a problem.  The result°dONLNd>T<`÷(|ZZof a multicolored copy is that all objects copy in the same color, that of the foreground.°dONLNdôl<x0*5It is possible to work with an off-screen buffer and °dONLNdŒl0x˛)Ù.the old style colors, but it requires a lot of°dONLNd˝x<ÑV(†Zextra °dONLNd    xVÑ˛)Ywork.  Unless the objects are really complex, then it is probably easier to just draw the°dONLNd    ]Ñ<êfl(¨Z"objects directly into your window. ◊X◊
  8415. *@Old Style Colors(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  8416. currentdict /bu known {bu}if
  8417. userdict /_cv known not{userdict /_cv 30 dict put}if
  8418. _cv begin
  8419. /bdf{bind def}bind def
  8420. currentscreen/cs exch def/ca exch def/cf exch def
  8421. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8422. /ss{//cf //ca //cs setscreen}bdf
  8423. /stg{ss setgray}bdf
  8424. /strgb{ss setrgbcolor}bdf
  8425. /stcmyk{ss cvcmyk}bdf
  8426. /min1{dup 0 eq{pop 1}if}bdf
  8427. end
  8428. currentdict /bn known {bn}if
  8429. †øÿ◊#ˇ ˇˇˇˇ#◊ 
  8430. IR,Times
  8431. .+6-Macintosh Technical Notes /4/˘
  8432. °dONLNd)*/One other limitation does exist.  Consider the °dONLNd/)⁄)ÿ-following code sample.  One would assume that°dONLNd])5√(Q6$this sample would work at all times.,
  8433. Courier
  8434.     °dONLNdÇALÅ*    SetPort (myPort);°dONLNdòKV≥*
  8435.     savedFG := myPort^.fgColor;°dONLNd∏U`5*
  8436. 9    ForeColor (redColor);            {or any other color}°dONLNdÚitÃ*$    {...drawing takes place here...}°dONLNd}àê*    ForeColor (savedFG);
  8437. °dONLNd0î†7*=Surprise.  It does not always work.  The saved value for the °dONLNdmì7üh(ºUfgColor°dONLNdtîh†ê)1
  8438.  field of °dONLNd~îꆢ)(the °dONLNdÇì¢ü⁄)GrafPort°dONLNdã°≠Œ(…6(is not a classic QuickDraw color if the °dONLNd≥†Œ¨)∂GrafPort°dONLNdª°≠C)8 is actually a °dONLNd †C¨Ç)=    CGrafPort°dONLNd”°Ç≠º)?.  If dealing °dONLNd·°º≠⁄):with a°dONLNdË≠πW(÷6    CGrafPort°dONLNdÒÆW∫q)?, the °dONLNd˜≠qπ¢)fgColor°dONLNd˛Æ¢∫$)1 field actually contains the °dONLNdÆ$∫⁄)Ç%foreground color’s entry in the color°dONLNdAª«ó(„6table, so the second call to °dONLNd^∫óΔ›)
  8439. _ForeColor°dONLNdhª›«R)F really messes things up.°dONLNdÇ‘‡¿(¸6$The proper way to set and reset the °dONLNd¶‘¿‡î)®*foreground color with classic QuickDraw’s °dONLNd–”îfl⁄)‘
  8440. _ForeColor°dONLNd€‡Ïj(6call is as follows:
  8441.     °dONLNdÔ¯Å*    SetPort (myPort);°dONLNd
  8442. ≥*
  8443.     savedFG := myPort^.fgColor;°dONLNd% 5*
  8444. 9    ForeColor (redColor);            {or any other color}°dONLNd_ +Ã*$    {...drawing takes place here...}°dONLNdÑ4?ä*J    myPort^.fgColor := savedFG;      {manually stuff the old fgColor back}°dONLNdœ>I£*
  8445. O    If (32BQD = TRUE) Then           {32BQD is a flag which is made and set by}°dONLNdHS≤*
  8446. R        PortChanged (myPort);        {the application; to set it, the application}°dONLNdrR]∑*
  8447. S                                     {needs to check _Gestalt for 32-Bit QuickDraw}
  8448. °dONLNdΔiu≈*&This Note also applies to the routine °dONLNdÏh≈t )≠
  8449. _BackColor°dONLNdˆi u)F.
  8450. °dONLNd¯çúj(∏6
  8451. What Works
  8452. °dONLNd®¥Q* The easiest °dONLNd®Q¥⁄)9Lway to work with these limited colors is to use pictures.  When you draw the°dONLNd\¥¿≠(‹6Oimages, you should draw into a picture.  Then when you want to draw the images °dONLNd´¥≠¿⁄(‹À    into your°dONLNdµ¡Õ¢(È6window or to a printer, call °dONLNd“¿¢È)ä _DrawPicture°dONLNdfi¡ˆÕπ)T).  Pictures work well with the old style °dONLNd¡πÕ⁄)√colors,°dONLNdÕŸå(ı6Land you don’t need to worry about making sure that the forecolor is current °dONLNd[ÕåŸ⁄(ı™
  8453. when you draw°dONLNdiŸÂq(6into your window.°dONLNd{Ò˝H*    Once you °dONLNdÑÒH˝⁄)0Uhave the picture, you can use it to draw into the screen or to the printer port.  You°dONLNd⁄˛
  8454. A(&6    can also °dONLNd„˛A
  8455. d))set the °dONLNdνd    ∏)# WindowRecord°dONLNd˜˛∏
  8456. ¡)Ts °dONLNd˘˝¡    )        windowPic°dONLNd˛
  8457. H)? to equal your °dONLNd˝H    £)H
  8458. PictureHandle°dONLNd˛£
  8459. ⁄)[  so updates°dONLNd*
  8460.  (26"are handled by the Window Manager.
  8461. °dONLNdM.=$*'#What Do Those Constants Mean Anyway
  8462. °dONLNdqIUÈ*,Each of the constants contains nine bits of °dONLNdùIÈU⁄)—0information, and each bit has a special meaning.°dONLNdœUaM(}6DFigure 1 illustrates the meaning of each of the bits, while Table 1 °dONLNdUMa⁄(}kshows how each of the color°dONLNd/amΔ(â6(constants fills in the appropriate bits. ◊4◊˘
  8463. *c2) of 3(Ï¥Old Style ColorsˇF◊#ˇ ˇˇˇˇ#◊ 
  8464. IR,Times
  8465. .+Z-Developer Support Center(-Ë August 1990 /X/†09†Ç
  8466. <√Ã≤òS,„S,„<√Ã≤Áˇ˛Ç ¸p¸¯p 0Ä ÄÄà`HÊsÄ(  Ñí$Ç¯H` Ñí#à Ñí Ç  Ñí$Ç ¸@ Ñ‚ ÑÄ H x‡¯ 0Áˇ˛˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝    @  ˝    @  $«    @  %$Ä    @  $‰Ä    @  %$Ä    @  %$Ä    @  ‰Ä    @  ˛˛    @  ˛˚    @  ˜    @  ˜    @  ˜    @  ˛@@    @  ˛¿@    @  ˛LsÊ    @  ˛RîíI    @  ˛NóíG    @  ˛RîI    @  ˛RîíI    @  ˛Ns'    @  ¸˝    @  ¸`˙   @  Ù   @  Ù   @  ˚ f˝   @  ˚ "˝   @  ˚F"2   @  ˚I"J   @  ˙è"IP   @  ˙à"IP   @  ˙â"H†   @  ˙Ü"0†¸
  8467.   @  Ò
  8468.   @  Ò
  8469.   @  Ò
  8470.   @  Ò
  8471.   @  Ò
  8472.   @  ˜0@  @  ˜ê@  @  ˜ëåH  @  ˜RP  @  ˜ë–`  @  ˜íP`  @  ˜íRP  @  ˜ÃH  @  Ó
  8473.  @  Ó
  8474.  @  Ó
  8475.  @  Ó
  8476.  @  Û  @  ÛÄ  @  Ûò‡ @  Û•  @  Û=  @  Û
  8477. !  @  Û    %  @  Ûò‡ @  Ó
  8478.  @   Î@   Î@   Î@  Ò¸@  ÒÄ˝@  Ò
  8479. c@  Ò
  8480. îí@  Ò
  8481.     ê˜í@  Ò
  8482. êÑ@  Ò
  8483. êîí@  Ò
  8484. c@   Î@  Ë  Ë  Ë  Ë  
  8485. ÌyIJ  
  8486. ÌDIJ  
  8487. Ì    Dâ0  
  8488. Ì    xâH  
  8489. Ì    Dâx  
  8490. Ì    Dâ@  
  8491. Ì    DâH  
  8492. Ì    xá0  Ë  Ë  Â Â Â Â  Ù@ı  ˙¸    áò ` $˛ ˙¸    ÑH Ä"$˛ ˙âã1ÅHΔ$ù¿G3òé ˙äLJAâ)(HÄDë$I ˙S»3¡HË0ÚHÄDë<‚I ˙R
  8493. I(0HÄÑë I ˙"HJ@ÑI)(HÄÑë$I ˙!à1ÄáàÊ$àÑÑêòâ 
  8494. Ù@¸˘     Ó˘ „„„„„„ÒÄı@˜0@ à3 ˜êê@ D ˜ìv1ëåHí9ú¿ Ó˜TòIIRPí™$â D˜TêI9ë–a‰í™$âÁíD˜4êIIíP`íD$âD˜4êIIíRPíD$â D ˜I9ÃH D$Ñ¿ D  Òĸ ˚@Î@˙†É
  8495. IR
  8496. °dONLNdˇˇ(·ıFigure 1–Bit Definitions
  8497. °dONLNdˇˇ(πblack°dONLNdˇˇ),white°dONLNdˇˇ)4red°dONLNdˇˇ)'green°dONLNdˇˇ)/blue°dONLNdˇˇ)-cyan°dONLNdˇˇ)$magenta°dONLNdˇˇ)0yellow°dONLNdˇˇ(º(33)°dONLNdˇˇ)-(30)°dONLNdˇˇ)*(209)°dONLNdˇˇ)-(329)°dONLNdˇˇ)-(389)°dONLNdˇˇ)-(269)°dONLNdˇˇ)-(149)°dONLNdˇˇ)'(89) |°dONLNdˇˇ(~Cyan°dONLNdˇˇ)E0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)(1°dONLNdˇˇ)20°dONLNdˇˇ)0°dONLNdˇˇ('~Magenta°dONLNdˇˇ)E0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)(0°dONLNdˇˇ)21°dONLNdˇˇ)0°dONLNdˇˇ(2~Yellow°dONLNdˇˇ)E0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)20°dONLNdˇˇ)1°dONLNdˇˇ(=~Black°dONLNdˇˇ)E1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)20°dONLNdˇˇ)0°dONLNdˇˇ(H~Red°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)21°dONLNdˇˇ)1°dONLNdˇˇ(S~Green°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)(1°dONLNdˇˇ)20°dONLNdˇˇ)1°dONLNdˇˇ(^~Blue°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)(1°dONLNdˇˇ)21°dONLNdˇˇ)0°dONLNdˇˇ(i~Inverse°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)20°dONLNdˇˇ)0°dONLNdˇˇ(t~Normal°dONLNdˇˇ)E1°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)(1°dONLNdˇˇ)21°dONLNdˇˇ)1 v|v
  8498. °dONLNdˇˇ(åÂTable 1–Color-Bit Correlation°dONLNdˇˇ(ºZFurther Reference: øXø°dONLNdˇˇ+
  8499. •°dONLNdˇˇ)Inside Macintosh°dONLNdˇˇ)Q, Volume I-173, QuickDraw°dONLNdˇˇ(’l•°dONLNdˇˇ)Technical Note M.IM.Copybits —°dONLNdˇˇ+$ Of Time and Space and _CopyBits ◊X◊
  8500. (ÏZOld Style Colors(Ï3) of 3ˇj◊#ˇ ˇˇˇˇ#◊†Ç 
  8501. /ZÅ#
  8502.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8503. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8504. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8505. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8506. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8507.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8508. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8509. IR.°dONLNdz<çΔ(ßZ*Things You Wanted to Know About _PackBits*°dONLNd,årüA+6*But Were Afraid to Ask
  8510. °dONLNdDû<≠r(…ZImaging°dONLNdLûõ≠˛(…π
  8511. M.IM.PackBits
  8512. °dONLNdZπ<≈t(·Z Revised by:°dONLNdfπÑ≈])H,Guillermo Ortiz, Jon Zap, and Forrest Tanaka°dONLNdìπæ≈˛(·‹ January 1992°dONLNd†≈<—q(ÌZ Written by:°dONLNd¨≈Ñ—À)H
  8513. Cameron Birse°dONLNd∫≈±—˛(Ìœ
  8514. November 1987°dONLNd»fi<Ír(Z?This Technical Note describes the format of data packed by the °dONLNdfirÍø(êToolbox utility ,
  8515. Courier°dONLNd›øÈ˛)M    _PackBits°dONLNd!Î<˜’(Zand documents a change to the °dONLNd?Í’ˆ
  8516. )ôsrcBytes°dONLNdGÎ
  8517. ˜â)8 limit and possible worst °dONLNdaÎâ˜˛)|case. Although you can°dONLNdx¯<⁄( Zsimply unpack this data using °dONLNdñ˜⁄')û _UnPackBits°dONLNd°¯'˛)M), Apple provides this information for the°dONLNdÀ<A(-Z6terminally curious and for those manipulating MacPaint
  8518.     °dONLNdAH(*_®
  8519. °dONLNdHÏ+! documents or PICT files by hand.°dONLNd%<t(9Z    Warning: °dONLNd.tH)8-This format information is subject to change.°dONLNd\<)Ô(EZChanges since November 1990:°dONLNdxÔ):)≥ A warning has °dONLNdá:)˙)K'been added about the handling of a flag°dONLNdÆ˙)˛)¿-°dONLNdØ)<5º(QZcounter byte value of -128. `X`
  8520. °dONLNdÀZ<i“*4Length Doesn’t Matter
  8521. °dONLNd·v<Ç]*Inside °dONLNdËv]Çé)!    Macintosh°dONLNdÒvéÇô)16, Volume I-470, describes the Pascal interface to the °dONLNd'uôÅÿ(û∑    _PackBits°dONLNd0vÿDz)? trap as°dONLNd9Ç<éc(™Zfollows:
  8522.     °dONLNdBö<•|*@    PROCEDURE PackBits(VAR srcPtr,dstPtr:Ptr; srcBytes:INTEGER);
  8523. °dONLNdɱ<Ωò*The accompanying °dONLNdî±òΩ‡)\text states that °dONLNd•∞‡º)HsrcBytes°dONLNd≠±Ω˛)8., the length of your uncompressed data, should°dONLNd‹æ< Ù(ÊZ)not be greater than 127, and that in the °dONLNdæÙ ∑)∏'worst case, the compressed data can be °dONLNd,Ω∑…˛)√
  8524. srcBytes +°dONLNd7 <÷C(ÛZ1°dONLNd8ÀC◊Ó)U. To pack more than 127 bytes, you had to break the data up into 127-byte groups and °dONLNdçÀÓ◊˛(Û call°dONLNdí◊<„{(Z    _PackBits°dONLNdõÿ{‰¸)? on each group. Beginning °dONLNdµÿ¸‰˛)Å5with system software version 6.0.2, this limit of 127°dONLNdΉ<Î( Z"bytes is no longer valid. The new °dONLNd
  8525. ‰Î˛)Ø4limit is 32,767 bytes, which is the maximum positive°dONLNdBÒ<˝}(Z number that °dONLNdN}¸µ)AsrcBytes°dONLNdVÒµ˝—)8 can °dONLNd[Ò—˝˛)7hold. The worst case can be determined according to the°dONLNdì˝<    ï(%Zfollowing formula:
  8526.     °dONLNd¶< ˇ*'    (srcBytes + (srcBytes+126) DIV 127)
  8527. °dONLNdŒ+<7,*1which is comparable to what you would get if you °dONLNdˇ+,7˛)*broke up the data into 127-byte groups and°dONLNd*7<C (_Z,picked up an additional byte for each group.
  8528. °dONLNdW[<jW*'$Mommy, How Do They Make Packed Bits?
  8529. °dONLNd|v<Ç›*VThe first byte is a flag-counter byte that specifies whether or not the the following °dONLNd“v›Ç˛(û˚data is°dONLNd⁄Ç<é¥(™Zpacked, and the number °dONLNdÒÇ¥é˛)xDof bytes involved. If this first byte is a negative number, then the°dONLNd6é<ö (∂Z,following data is packed. In this case, the °dONLNdbé ö˛)œ.number is the two’s complement of a zero-based°dONLNdëö<¶z(¬Z
  8530. count of the °dONLNdûöz¶˛)>Knumber of times the data byte repeats when expanded. There is one data byte ◊X◊
  8531. (ÏZ)Things You Wanted to Know About _PackBits(Ï1) of 4ˇ°¿Ù%%DSIDICT:_cv
  8532. currentdict /bu known {bu}if
  8533. userdict /_cv known not{userdict /_cv 30 dict put}if
  8534. _cv begin
  8535. /bdf{bind def}bind def
  8536. currentscreen/cs exch def/ca exch def/cf exch def
  8537. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8538. /ss{//cf //ca //cs setscreen}bdf
  8539. /stg{ss setgray}bdf
  8540. /strgb{ss setrgbcolor}bdf
  8541. /stcmyk{ss cvcmyk}bdf
  8542. /min1{dup 0 eq{pop 1}if}bdf
  8543. end
  8544. currentdict /bn known {bn}if
  8545. †ø$◊#ˇ ˇˇˇˇ#◊ 
  8546. IR,Times
  8547. .+6-Macintosh Technical Notes /4/˘
  8548. °dONLNd)Ò*.following this first byte in packed data. The °dONLNd.Ò)⁄)Ÿ1byte after the data byte is the next flag-counter°dONLNd`)50(Q6byte.°dONLNdfAM*8If the flag-counter byte is a positive number, then the °dONLNdûAM⁄)˝)following data is unpacked. In this case,°dONLNd»MYò(u6Qthe number is a zero-based count of the number of incompressible data bytes that °dONLNdMòY⁄(u∂
  8549. follow. There°dONLNd'Yeâ(Å6Pare (flag-counter+1) data bytes following the flag-counter byte. The byte after °dONLNdwYâe⁄(Åßthe last data byte°dONLNdäeqü(ç6is the next flag-counter byte.°dONLNd©}âø*#Note that there is no way to know, °dONLNdÃ}øâ⁄)ß:given a pointer to the start of packed data, when you have°dONLNdâï¨(±6reached the end of the packed °dONLNd%â¨ï⁄)î;data. This is why you need to know either the length of the°dONLNdañ¢(æ64packed or unpacked data before you start unpacking. ,
  8550. Courier°dONLNdïï°a)¸ _UnPackBits°dONLNd†ña¢æ)M requires the length °dONLNdµñæ¢⁄)]of the°dONLNdº¢Æ_( 6unpacked data.°dONLNdÀª«L*Warning:°dONLNd‘∫`Δü)H    _PackBits°dONLNd›ªü«)? never generates the °dONLNdÚª«∂)h"value -128 ($80) as a flag-counter°dONLNd«`”3(Ô~'byte, but a few PackBits-like routines °dONLNd<«3”∂)”that are built into some°dONLNdU‘`‡Æ(¸~applications do. °dONLNdf”Æfl˚)N _UnpackBits°dONLNdq‘˚‡∂)M' handles this situation by skipping any°dONLNdô‡`ϵ(~flag-counter byte °dONLNd´‡µÏ∂)U5with this value and interpreting the next byte as the°dONLNd·Ï`¯i(~3next flag-counter byte. If you’re writing your own °dONLNdÏi¯∂(áUnpackBits-like°dONLNd$¯`z( ~=routine, make sure it handles this situation in the same way.°dONLNdb≤(86Consider the following example:°dONLNdÇ(4a*Unpacked data:
  8551.     °dONLNdë@Kè*K    AA AA AA 80 00 2A AA AA AA AA 80 00 2A 22 AA AA AA AA AA AA AA AA AA AA
  8552. °dONLNd›WcÉ*After being packed by °dONLNdÛVÉb¬)k    _PackBits°dONLNd¸W¬c≈)?:
  8553.     °dONLNd˛ozq(ñ6E    FE AA                    ; (-(-2)+1) = 3 bytes of the pattern $AA°dONLNdDyÑS*
  8554. ?    02 80 00 2A              ; (2)+1 = 3 bytes of discrete data°dONLNdÑÉéq*
  8555. E    FD AA                    ; (-(-3)+1) = 4 bytes of the pattern $AA°dONLNd çòS*
  8556. ?    03 80 00 2A 22           ; (3)+1 = 4 bytes of discrete data°dONLNd
  8557. ó¢v*
  8558. F    F7 AA                    ; (-(-9)+1) = 10 bytes of the pattern $AA
  8559. °dONLNdQ≠π7*           or
  8560.     °dONLNd[≈–*0    FE AA 02 80 00 2A FD AA 03 80 00 2A 22 F7 AA°dONLNdåœ⁄Ù*
  8561. ,    *     *           *     *              *
  8562. °dONLNdπÊÚI*
  8563. The bytes °dONLNd√ÊIÚj)1=with the asterisk (*) under them are the flag-counter bytes. °dONLNdÂjÒ©(à    _PackBits°dONLNd    Ê©Ú⁄)?
  8564.  packs the°dONLNdÚ˛}(6data only when there °dONLNd)Ú}˛⁄)eIare three or more consecutive bytes with the same data; otherwise it just°dONLNds˛
  8565. (&68copies the data byte for byte (and adds the count byte).°dONLNd¨#7*Note:°dONLNd≤<#Ò)$#The data associated with some PICT °dONLNd’Ò#H)µopcodes, $0098 (°dONLNdÂH"ú)W PackBitsRect°dONLNdÒú#∂)T) and°dONLNd˜$<0a(LZ$0099 °dONLNd˝$a0e)%(°dONLNd˛#e/≤) PackBitsRgn°dONLNd    $≤0Ï)M ), contain °dONLNd#Ï/):PixData°dONLNd$0∂)1 which is basically made of°dONLNd70<<{(YZ    _PackBits°dONLNd@1{=ÿ)? data. It should be °dONLNdT1ÿ=Ö)]#noted, though, that the format for °dONLNdw0Ö<∂)≠PixData°dONLNd><Jn(fZ includes a °dONLNdä=nI≠)2    byteCount°dONLNdì>≠J∞)?: or length in addition to the data described in this Note.°dONLNdŒVb_(~6DFor example, the following is the result of decoding a sample PICT2:
  8566.     °dONLNd    nyÅ*data 'PICT' (25534) {°dONLNd    )xÉl*
  8567. D    0936 0000 0000 0007 001E                /* pic size, picFrame */°dONLNd    nÇçl*
  8568. D    0011 02FF                               /* pict2              */°dONLNd    ≥åól*
  8569. D    0C00                                    /* header             */°dONLNd    ¯ñ°l*
  8570. D         FFFF FFFF 0000 0000 0000 0000 001E 0000 0007 0000 0000 0000°dONLNd
  8571. =†´l*
  8572. D    001E                                    /* def hilite         */ ◊4◊˘
  8573. *%2) of 4(Ï;)Things You Wanted to Know About _PackBitsˇfi◊#ˇ ˇˇˇˇ#◊ 
  8574. IR,Times
  8575. .+Z-/Developer Support Center                       (-Á January 1992 /X/,
  8576. Courier
  8577.     °dONLNd<(ê(DZD    0001                                    /* clipRgn            */°dONLNdE'<2·*
  8578. !         000A 0000 0000 0007 001E°dONLNdg1<<ê*
  8579. D    0098                                    /* PackBitsRect       */°dONLNd¨;<Fê*
  8580. D         801E                               /* rowbytes of 30     */°dONLNdÒE<Pê*
  8581. D         0000 0000 0007 001E                /* Bounds             */°dONLNd6O<Zê*
  8582. D         0000                               /* packType           */°dONLNd{Y<dê*
  8583. D         0000                               /* version            */°dONLNd¿c<nê*
  8584. D         0000 0000                          /* packSize           */°dONLNdm<xê*
  8585. D         0048 0000                          /* hRes               */°dONLNdJw<Çê*
  8586. D         0048 0000                          /* vRes               */°dONLNdèÅ<åê*
  8587. D         0000                               /* pixelType          */°dONLNd‘ã<ñê*
  8588. D         0008                               /* pixelSize          */°dONLNdï<†ê*
  8589. D         0001                               /* cmpCount           */°dONLNd^ü<™ê*
  8590. D         0008                               /* cmpSize            */°dONLNd£©<¥ê*
  8591. D         0000 0000                          /* planeBytes         */°dONLNdË≥<æê*
  8592. D         0000 1F10                          /* pmTable            */°dONLNd-Ω<»ê*
  8593. D         0000 0000                          /* pmReserved         */°dONLNdr«<“Ø*
  8594.         /*color table*/°dONLNdä—<‹ê*
  8595. D              0000 4CBC                     /* ctSeed             */°dONLNdœ€<Êê*
  8596. D              8000                          /* ctFlags            */°dONLNdÂ<ê*
  8597. D              00FF                          /* ctSize             */°dONLNdYÔ<˙˙*
  8598. &                   0000 FFFF FFFF FFFF°dONLNdĢ<ê*
  8599. D                   ...                 /* 254 ColorSpec's omitted */°dONLNd≈<˙*
  8600. &                   0000 0000 0000 0000°dONLNdÏ
  8601. <ê*
  8602. D         0000 0000 0007 001E                /* srcRect            */°dONLNd1<"ê*
  8603. D         0000 0000 0007 001E                /* dstRect            */°dONLNdv!<,ê*
  8604. D         0000                               /* srcCopy            */°dONLNdª5<@m*=         /* Now we have the scan line data packed as follows:°dONLNd˘?<Jï*
  8605. E            [bytecount for current scan line] [data as defined above]°dONLNd?I<T§*
  8606. H            If rowBytes is > 250 then byteCount is a word else is a byte°dONLNdàS<^'*
  8607. /            (in this case, byteCount is a byte)°dONLNd∏]<hc*
  8608. ;            note that each unpacked row adds to 30 rowBytes°dONLNdÙg<rs*
  8609.          */°dONLNd{<Ür*>         /* line 1, byte count is 2 (best case for a row)   */°dONLNd?Ö<ês*
  8610.          02°dONLNdKè<ör*
  8611. >            E3 FF                /* -(-29) + 1 = 30 FF's    */°dONLNdäô<§r*
  8612. >         /* line 2, byte count is 19 (0x13)                 */°dONLNd…£<Æs*
  8613.          13°dONLNd’≠<∏r*
  8614. >            01 FF 23             /* 1+1 data bytes          */°dONLNd    ∑<¬r*
  8615. >            FE 00                /* -(-2)+1 0's             */°dONLNd    S¡<Ãr*
  8616. >            FC 23                /* -(-4)+1 0x23's          */°dONLNd    íÀ<÷r*
  8617. >            FE 00                /* 3 0's                   */°dONLNd    —’<‡r*
  8618. >            FC 23                /* 5 0x23's                */°dONLNd
  8619. fl<Ír*
  8620. >            FE 00                /* 3 0's                   */°dONLNd
  8621. OÈ<Ùr*
  8622. >            FC 23                /* 5 0x23's                */°dONLNd
  8623. éÛ<˛r*
  8624. >            FE 00                /* 3 0's                   */°dONLNd
  8625. Õ˝<r*
  8626. >            00 FF                /* 1 data byte             */°dONLNd <r*
  8627. >         /* line 3, byte count is 28                        */°dONLNd K<s*
  8628.          1C°dONLNd W<&r*
  8629. >            02 FF 00 23          /* 3 data bytes            */°dONLNd ñ%<0r*
  8630. >            FE 00                /* 3 0's                   */°dONLNd ’/<:r*
  8631. >            FE 23                /* 3 0x23's                */°dONLNd 9<Dr*
  8632. >            01 00 23             /* 2 data bytes            */°dONLNd SC<Nr*
  8633. >            FE 00                /* 3 0's                   */°dONLNd íM<Xr*
  8634. >            FE 23                /* 3 0x23's                */°dONLNd —W<br*
  8635. >            01 00 23             /* 2 data bytes            */°dONLNd
  8636. a<lr*
  8637. >            FE 00                /* 3 0's                   */°dONLNd
  8638. Ok<vr*
  8639. >            FE 23                /* 3 0x23's                */°dONLNd
  8640. éu<Är*
  8641. >            04 00 23 00 00 FF    /* 5 data bytes            */°dONLNd
  8642. Õ<är*
  8643. >         /* line 4, byte count is 31 (worst case for a row) */°dONLNd â<îs*
  8644.          1F°dONLNdì<ûr*
  8645. >            03 FF 00 00 23       /* 4 data bytes            */°dONLNdWù<®r*
  8646. >            FE 00                /* 3 0's                   */ ◊X◊
  8647. *()Things You Wanted to Know About _PackBits(Ï3) of 4ˇ◊#ˇ ˇˇˇˇ#◊ 
  8648. IR,Times
  8649. .+6-Macintosh Technical Notes /4/˘,
  8650. Courier
  8651.     °dONLNd(N*>            00 23                /* 1 data byte             */°dONLNd?'2N*
  8652. >            FE 00                /* 3 0's                   */°dONLNd~1<N*
  8653. >            00 23                /* 1 data byte             */°dONLNdΩ;FN*
  8654. >            FE 00                /* 3 0's                   */°dONLNd¸EPN*
  8655. >            00 23                /* 1 data byte             */°dONLNd;OZN*
  8656. >            FE 00                /* 3 0's                   */°dONLNdzYdN*
  8657. >            00 23                /* 1 data byte             */°dONLNdπcnN*
  8658. >            FE 00                /* 3 0's                   */°dONLNd¯mxN*
  8659. >            00 23                /* 1 data byte             */°dONLNd7wÇN*
  8660. >            FE 00                /* 3 0's                   */°dONLNdvÅåN*
  8661. >            02 23 00 FF          /* 3 data bytes            */°dONLNdµãñN*
  8662. >         /* line 5, byte count is 28                        */°dONLNdÙï†O*
  8663.          1C°dONLNdü™N*
  8664. >            01 FF 00             /* 2 data bytes            */°dONLNd?©¥N*
  8665. >            FE 23                /* 3 0x23's                */°dONLNd~≥æN*
  8666. >            01 00 23             /* 2 data bytes            */°dONLNdΩΩ»N*
  8667. >            FE 00                /* 3 0's                   */°dONLNd¸«“N*
  8668. >            FE 23                /* 3 0x23's                */°dONLNd;—‹N*
  8669. >            01 00 23             /* 2 data bytes            */°dONLNdz€ÊN*
  8670. >            FE 00                /* 3 0's                   */°dONLNdπÂN*
  8671. >            FE 23                /* 3 0x23's                */°dONLNd¯Ô˙N*
  8672. >            01 00 23             /* 2 data bytes            */°dONLNd7˘N*
  8673. >            FE 00                /* 3 0's                   */°dONLNdvN*
  8674. >            FE 23                /* 3 0x23's                */°dONLNdµ
  8675. N*
  8676. >            00 FF                /* 1 data byte             */°dONLNdÙ"N*
  8677. >         /* line 6, byte count is 18                        */°dONLNd3!,O*
  8678.          12°dONLNd?+6N*
  8679. >            00 FF                /* 1 data byte             */°dONLNd~5@N*
  8680. >            FC 23                /* 5 0x23's                */°dONLNdΩ?JN*
  8681. >            FE 00                /* 3 0's                   */°dONLNd¸ITN*
  8682. >            FC 23                /* 5 0x23's                */°dONLNd;S^N*
  8683. >            FE 00                /* 3 0's                   */°dONLNdz]hN*
  8684. >            FC 23                /* 5 0x23's                */°dONLNdπgrN*
  8685. >            FE 00                /* 3 0's                   */°dONLNd¯q|N*
  8686. >            FD 23                /* 4 0x23's                */°dONLNd7{ÜN*
  8687. >            00 FF                /* 1 data byte             */°dONLNdvÖêN*
  8688. >         /* line 7, byte count is 2 (best case for a row)   */°dONLNdµèöO*
  8689.          02°dONLNd¡ô§N*
  8690. >            E3 FF                /* 30 0xFF's               */°dONLNd    £ÆN*
  8691. >         00  /* pad so next command starts at word boundary */°dONLNd    ?∑¬N*>    00FF                         /*end of pic               */°dONLNd    ~¡Ã"*
  8692. };
  8693. °dONLNd    ÅÔ˚Ç*/Further Reference: 4˘°dONLNd    î¸*.+
  8694. •°dONLNd    ñ¸<ç)Inside Macintosh°dONLNd    ¶¸çB)Q%, Volume I-465, The Toolbox Utilities°dONLNd    Ã*.(0H•°dONLNd    Œ<ç)Inside Macintosh°dONLNd    fiç/)Q, Volume V-39, Color QuickDraw°dONLNd    ˝* .(<H•°dONLNd    ˇ< Ù)!Technical Note M.PT.MacPaintDoc —°dONLNd
  8695. # `,Á+$  MacPaint Document Format°dONLNd
  8696. =,*8‹(TH&MacPaint is a registered trademark of °dONLNd
  8697. c,‹8‰)≤C
  8698. °dONLNd
  8699. d,‰8)LARIS
  8700. °dONLNd
  8701. i,8A)
  8702.  Corporation. ◊4◊˘
  8703. (Ï64) of 4(Ï;)Things You Wanted to Know About _PackBitsˇ ◊#ˇ ˇˇˇˇ#◊†Ç 
  8704. /ZÅ#
  8705.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8706. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8707. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8708. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8709. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8710.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8711. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8712. IR.°dONLNdz<çï(ßZ'Palette Manager Changes in System 6.0.2
  8713. °dONLNd(å<õr*Imaging°dONLNd0å8õ˛)¸M.IM.PaletteManagerChanges
  8714. °dONLNdKß<≥q(œZ Written by:°dONLNdWßÑ≥Œ)HGuillermo Ortiz°dONLNdgßæ≥˛(œ‹ October 1988°dONLNdtø<Àl(ÁZ>This Technical Note describes the changes and enhancements to °dONLNd≤ølÀ˛(Áäthe Palette Manager in System°dONLNd–À<◊Ê(ÛZ#Software 6.0.2 and future versions. X
  8715. °dONLNdÙ¸< ª*4Application Palette
  8716. °dONLNd<#ö*MApplications now have the ability to define a default palette for the system °dONLNdUö#˛(?∏to use when it needs°dONLNdj#</Û(KZ'to define the color environment (i.e., °dONLNdë#Û/˛)∑4when it creates a color window without an associated°dONLNdΔ/<;÷(WZ"palette or displays a dialog box).°dONLNdÈG<S2*6The application palette feature is especially cool in °dONLNdG2S˙)ˆ(cases where a color application uses old°dONLNdGG˙S˛)»-°dONLNdHS<_fi({ZYstyle dialogs and alerts because without an application palette, the system will use the °dONLNd°Sfi_˛({¸default°dONLNd©_<k˝(áZ)palette to define the color environment. °dONLNd“_˝k˛)¡5 Since the system uses the default palette, the color°dONLNdk<wì(ìZenvironment may °dONLNdkìwΩ)Wchange (°dONLNd kΩwœ)*will°dONLNd$kœw˛): change in 16-color mode) to cause some “cosmic” colors to°dONLNd_w<Ɉ(üZ'appear in the active window.  Defining °dONLNdÜwˆÉ˛)∫8a default application palette with two colors, black and°dONLNdøÉ<èΩ(´Zwhite, solves this problem.°dONLNd€õ<ßÔ*(If the system needs a palette to define °dONLNdõÔ߲)≥9a color environment, it looks in the resource fork of the°dONLNd=®<¥î(–Zapplication for the ,
  8717. Courier°dONLNdQßî≥⁄)X
  8718. 'pltt' ID °dONLNd[ß⁄≥¯)F= 0 °dONLNd_®¯¥˛)8resource and uses the palette which it contains.  If the°dONLNdò¥<¿`(‹Zsystem °dONLNdü¥`¿˛)$Ycannot find this resource in the application’s resource fork, it will use its own default°dONLNd˘¡<Õå(ÈZpalette (resource °dONLNd ¿åÃÓ)P'pltt' ID = 0 °dONLNd¡ÓÕQ)bin the System file) if °dONLNd0¡QÕ˛)c&present, or, if necessary, it will use°dONLNdWÕ<ŸÎ(ıZ'the Palette Manager’s built-in palette.°dONLNdÊ<Ú†*>Once an application has set its color environment (by calling °dONLNdΩ†ÒÊ(æ
  8719. _InitMenus°dONLNd«ÊÊÚÙ)F, °dONLNd…ÊÙÚ˛)or°dONLNdÃÚ<˛ó(Z
  8720. _InitPalettes°dONLNdŸÛóˇƒ)[
  8721.  in weird °dONLNd„Ûƒˇ˛)-Binstances when there are no menus) it can find the default palette°dONLNd&< o((Z by calling °dONLNd1ˇo >)3GetPalette ( WindowPtr (-1) )°dONLNdN> ´)œ or change the default °dONLNde´ ˛)mpalette by calling°dONLNdx <£(5Z/SetPalette ( WindowPtr (-1), newDefPltt, true )°dONLNdß
  8722. £÷(5¡.  Note °dONLNdØ
  8723. ÷˛)3that the°dONLNd∏<&ñ(BZinitialization of the °dONLNdŒñ&))ZPalette Manager with a call to °dONLNdÌ)%o)ì
  8724. _InitMenus°dONLNd˜o&·)F is contrary to the way °dONLNd·&˛)rInside°dONLNd&<2m(NZ    Macintosh°dONLNd&m2N)1-, Volume V, The Palette Manager documents it.
  8725. °dONLNdMJ<Yfi(uZOne Palette, Many Ports
  8726. °dONLNdef<rÑ* You can now °dONLNdqfÑr*)H associate one palette with many °dONLNdëe*qi)¶    CGrafPort°dONLNdöfirÜ)? and °dONLNdüeÜq∑)CWindow°dONLNd¶f∑r˛)1 records, thus°dONLNdµr<~¶(öZsimplifying the use of °dONLNdÃr¶~˛)jEa single palette with multiple ports and windows; System Software 6.0°dONLNd~<äè(¶ZKand earlier require copies of the palette to use it with different windows. ◊X◊
  8727. *F'Palette Manager Changes in System 6.0.2(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  8728. currentdict /bu known {bu}if
  8729. userdict /_cv known not{userdict /_cv 30 dict put}if
  8730. _cv begin
  8731. /bdf{bind def}bind def
  8732. currentscreen/cs exch def/ca exch def/cf exch def
  8733. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8734. /ss{//cf //ca //cs setscreen}bdf
  8735. /stg{ss setgray}bdf
  8736. /strgb{ss setrgbcolor}bdf
  8737. /stcmyk{ss cvcmyk}bdf
  8738. /min1{dup 0 eq{pop 1}if}bdf
  8739. end
  8740. currentdict /bn known {bn}if
  8741. †øD◊#ˇ ˇˇˇˇ#◊ 
  8742. IR,Times
  8743. .+6-Macintosh Technical Notes /4/˘
  8744. °dONLNd)O*CAlthough this ability to associate one palette with multiple ports °dONLNdCO)⁄(Emand windows will allow the°dONLNd^*6P(R6
  8745. use of calls °dONLNdk*P6e)8like ,
  8746. Courier°dONLNdp)e5π) _PmForeColor°dONLNd|*π6“)T and °dONLNdÅ)“5&) _PmBackColor°dONLNdç*&6Q)T
  8747. , calling °dONLNdó)Q5¡)+_ActivatePalette°dONLNdß*¡6⁄)p with°dONLNd≠6B@(^6Ban off-screen port does nothing, and as a result, calling it with °dONLNdÔ6@B⁄(^^!an off-screen port will associate°dONLNdBNé(j6Qthe palette with the port but will not cause any change in the color environment.°dONLNdc[g*2One important implication of this feature is that °dONLNdïZf[)Ë
  8748. DisposeWindow°dONLNd¢[[gd)[ (°dONLNd§Zdfø)    
  8749. _DisposWindow°dONLNd±[øg⁄)[) will°dONLNd∏gs1(è6=not dispose of the associated palette automatically since it °dONLNdıg1s⁄(èO"may be allocated to other ports or°dONLNdsƒ(õ6Iwindows.  The only exception to this behavior is when an application has °dONLNdasƒ⁄(õ‚used°dONLNdfãz(®6_GetNewCWindow°dONLNdtÄzå)b" to create the window, there is a °dONLNdñã=)ô'pltt'°dONLNdúÄ=åæ)* resource with the same ID °dONLNd∑Äæå⁄)Åas the°dONLNdæçô‰(µ6+window, and the application has not called °dONLNdÈå‰ò1)à _GetPalette°dONLNdÙç1ôÅ)M for the window.
  8750. °dONLNd±¿w(‹6
  8751. Color Updates
  8752. °dONLNdÕŸ*1System version 6.0.2 also introduces a new call, °dONLNdDÃÿm(ı7 _NSetPalette°dONLNdPÕmŸ⁄)T, which complements°dONLNddŸÂe(6 _SetPalette°dONLNdo⁄eÊs)M.  °dONLNdrŸs«) _NSetPalette°dONLNd~⁄«Ê`)T has the same functionality as °dONLNdùŸ`Â≠)ô _SetPalette°dONLNd®⁄≠Ê⁄)M    , but the°dONLNd≤ÊÚP(6CUpdates°dONLNd∫ÁPÛˇ)8$ parameter has been modified from a °dONLNdfiÊˇÚ0)ØBoolean°dONLNdÂÁ0ÛM)1 to an °dONLNdÏÊMÚ~)Integer°dONLNdÛÁ~Ûµ)1  as follows:
  8753.     °dONLNdˇ
  8754. {(&6GPROCEDURE NSetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;°dONLNdI    <†+$
  8755. nCUpdates: INTEGER);°dONLNd^Y(:6
  8756. INLINE $AA95;
  8757. °dONLNdl)5l* _NSetPalette°dONLNdx*l6o)T °dONLNdy*o6)$changes the palette associated with °dONLNdù)5Y)´    dstWindow°dONLNd¶*Y6j)? to °dONLNd™)j5∞)
  8758. srcPalette°dONLNd¥*∞6⁄)F
  8759. .  It also°dONLNdø6B`(^6@records whether the window wants to receive updates as a result °dONLNdˇ6`B⁄(^~of a change to its color°dONLNdCO¶(k6environment.  If you want °dONLNd2B¶NÂ)é    dstWindow°dONLNd;CÂOÎ)? °dONLNd<CÎO⁄),to be updated whenever its color environment°dONLNdiP\W(x6
  8760. changes, set °dONLNdvOW[ñ)?    nCUpdates°dONLNdPñ\ß)? to °dONLNdÉOß[˚) pmAllUpdates°dONLNdèP˚\)T.  If °dONLNdïP\⁄)'you are only interested in updates when°dONLNdΩ\hW(Ö6    dstWindow°dONLNdΔ]Wifi)? is the active window, set °dONLNd·\fih)á    nCUpdates°dONLNdÍ]i0)? to °dONLNdÓ\0h}) pmFgUpdates°dONLNd˘]}iã)M.  °dONLNd¸]ãi⁄)If you are only°dONLNd jv§(í6interested in updates when °dONLNd'i§u„)å    dstWindow°dONLNd0j„vÈ)? °dONLNd1jÈvã)is not the active window, set °dONLNdOiãu )¢    nCUpdates°dONLNdXj v⁄)? to°dONLNd\vÇe(ü6 pmBkUpdates°dONLNdgweÉi)M.
  8761.     °dONLNdièö∏(∂6 { NSetPalette Update Constants }°dONLNd䣯^*pmNoUpdates = °dONLNdô£ÑÆ¢)l$8000;°dONLNd†£®Ɖ)$ {no updates}°dONLNd≠≠∏^(‘6pmBkUpdates = °dONLNdº≠Ñ∏¢)l$A000;°dONLNd√≠®∏%)${background updates only}°dONLNd›∑¬^(fi6pmFgUpdates = °dONLNdÏ∑Ѭ¢)l$C000;°dONLNdÛ∑®¬%)${foreground updates only}°dONLNd
  8762. ¡Ãc(Ë6pmAllUpdates = °dONLNd¡Ñâ)l$E000;°dONLNd$¡®ÃÈ)$
  8763. {all updates}
  8764. °dONLNd2◊„e(6 _SetPalette°dONLNd=ÿe‰¯)M! retains its syntax and function:
  8765.     °dONLNd_˚v(6FPROCEDURE SetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;°dONLNdß˙<õ+$
  8766. CUpdates: Boolean);°dONLNdªY(+6
  8767. INLINE $AA95;
  8768. °dONLNd…'7*Note:°dONLNdœ<'ò)$The trap words for °dONLNd‚ò&Ï)\ _NSetPalette°dONLNdÓÏ')T and °dONLNdÛ&P) _SetPalette°dONLNd˛P'S)M °dONLNdˇS'a)are°dONLNda'è)  identical.
  8769. °dONLNd?Ng(j6 CopyPalette
  8770.     °dONLNdZeI*=PROCEDURE CopyPalette (srcPalette, dstPalette: PaletteHandle;°dONLNdYd<o˙+$
  8771. &srcEntry,dstEntry,dstLength: INTEGER);°dONLNdÄnyY(ï6
  8772. INLINE $AAA1;
  8773. °dONLNdéÑêl* _CopyPalette°dONLNdöÖlë)T$ is a utility procedure that copies °dONLNdæÑêF)õ    dstLength°dONLNd«ÖFëI)? °dONLNd»ÖIë⁄)entries from the source palette°dONLNdËíû(∫61into the destination palette; the copy begins at °dONLNd    ëù8)ËsrcEntry°dONLNd    !í8ûU)8 and °dONLNd    &ëUùû)
  8774. dstEntry, °dONLNd    0íûû⁄)I
  8775. respectively. ◊4◊˘
  8776. (Ï62) of 3(ÏO'Palette Manager Changes in System 6.0.2ˇ8◊#ˇ ˇˇˇˇ#◊ 
  8777. IR,Times
  8778. .+Z-Developer Support Center(-Ê October 1988 /X/,
  8779. Courier
  8780. °dONLNd<)ê(FZ _CopyPalette°dONLNd ê*€)TJ will resize the destination palette when the number of entries after the °dONLNdV€*˛(F˘copy is°dONLNd^*<6Ø(RZgreater than the original.°dONLNdyB<Nê* _CopyPalette°dONLNdÖCêOƒ)T
  8781.  does not °dONLNdèCƒO⁄)4call °dONLNdîB⁄NJ)_ActivatePalette°dONLNd§CJO˛)p$, so the application is free to do a°dONLNd…O<[¡(wZKnumber of palette changes without causing a series of intermediate changes °dONLNdO¡[˛(wfl to the color°dONLNd!\<h(ÑZ)environment; the application should call °dONLNdJ[gt)»_ActivatePalette°dONLNdZ\th˛)p after completing all palette°dONLNdxh<tf(êZchanges.°dONLNdÅÅ<ç€*%If either of the palette handles are °dONLNd¶Ä€å)üNIL°dONLNd©Åç˜), °dONLNd´Ä˜åK) _CopyPalette°dONLNd∑ÅKçè)T does nothing. ◊X◊
  8782. (ÏZ'Palette Manager Changes in System 6.0.2(Ï3) of 3ˇn◊#ˇ ˇˇˇˇ#◊†Ç 
  8783. /ZÅ#
  8784.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8785. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8786. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8787. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8788. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8789.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8790. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8791. IR.°dONLNdˇˇ(õZPalette Manager Q&As
  8792. °dONLNdˇˇ*Imaging°dONLNdˇˇ(´|M.IM.PaletteMgr.Q&As
  8793. °dONLNdˇˇ(√Z Revised by:°dONLNdˇˇ)HDeveloper Support Center°dONLNdˇˇ(√‹ October 1992°dONLNdˇˇ(œZ Written by:°dONLNdˇˇ)HDeveloper Support Center°dONLNdˇˇ(œ‹ October 1990°dONLNdˇˇ(ÁZThis Technical Note contains a °dONLNdˇˇ)û9collection of Q&As relating to a specific topic—questions°dONLNdˇˇ(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNdˇˇ(Ûæthe DSC engineers.°dONLNdˇˇ(ˇZ
  8794. While DSC °dONLNdˇˇ)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdˇˇ( Z don’t have °dONLNdˇˇ)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNdˇˇ(Znew technical information and °dONLNdˇˇ)ù6updates to you quickly, saving the polish for when the°dONLNdˇˇ(#Z,information migrates into reference manuals.°dONLNdˇˇ*:Q&As are now included with Technical Notes to make access °dONLNdˇˇ(;âto technical updates easier for°dONLNdˇˇ(GZ/you. If you have comments or suggestions about °dONLNdˇˇ)Ú*Q&A content or distribution, please let us°dONLNdˇˇ(SZknow °dONLNdˇˇ) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNdˇˇ(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdˇˇ*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  8795. °dONLNdˇˇ*40Macintosh Palette Manager and offscreen graphics
  8796. °dONLNdˇˇ* Written:°dONLNdˇˇ)L7/22/91°dONLNdˇˇ(√ZLast reviewed:°dONLNdˇˇ)L8/1/92°dONLNdˇˇ(€Z8The Macintosh Palette Manager doesn’t work on offscreen °dONLNdˇˇ(€âenvironments the way you’d°dONLNdˇˇ(ÁZexpect. °dONLNdˇˇ)%WUnlike color windows, SetPalette will not change the offscreen’s color table; rather it°dONLNdˇˇ(ÛZ:just allows you to use PMForeColor and PMBackColor to set °dONLNdˇˇ(ÛÄ!the current drawing color in that°dONLNdˇˇ(ˇZ:environment. To change the offscreen’s color table you’ll °dONLNdˇˇ(ˇl&need to convert the palette to a color°dONLNdˇˇ( ZZtable and then set the resulting color table to the off screen. Calling Palette2CTab will °dONLNdˇˇ( ˝do the°dONLNdˇˇ(Zconverting for you.°dONLNdˇˇ*%To get around having to use palettes °dONLNdˇˇ)≠:to define the current drawing color in the off screen, you°dONLNdˇˇ(;Z8can always use Index2Color and then RGBForeColor to get °dONLNdˇˇ(;x"the color to be set for drawing. A°dONLNdˇˇ(GZ%remake of GiMeDaPalette code sample, °dONLNdˇˇ)Ω6available on the latest Developer CD Series disc, does°dONLNdˇˇ(SZ@offscreen drawing in place of having to continually copy a PICT. ◊X◊
  8797. *ôPalette Manager Q&As(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  8798. currentdict /bu known {bu}if
  8799. userdict /_cv known not{userdict /_cv 30 dict put}if
  8800. _cv begin
  8801. /bdf{bind def}bind def
  8802. currentscreen/cs exch def/ca exch def/cf exch def
  8803. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8804. /ss{//cf //ca //cs setscreen}bdf
  8805. /stg{ss setgray}bdf
  8806. /strgb{ss setrgbcolor}bdf
  8807. /stcmyk{ss cvcmyk}bdf
  8808. /min1{dup 0 eq{pop 1}if}bdf
  8809. end
  8810. currentdict /bn known {bn}if
  8811. †ø\◊#ˇ ˇˇˇˇ#◊ 
  8812. IR,Times
  8813. .+6-Macintosh Technical Notes /4/˘
  8814. °dONLNd)8ñ*'8RestoreDeviceClut and color flash when application quits
  8815. °dONLNd98D>* Written:°dONLNdB8dDà)L8/23/91°dONLNdJDP](l6Last reviewed:°dONLNdYDdPÇ)L8/1/92°dONLNd`\h8(Ñ6When °dONLNde\8h⁄) Umy application, which uses a color palette, quits, there is momentary but distracting°dONLNdªhtC(ê6<flash of weird colors in the Finder windows and the desktop °dONLNd˜hCt⁄(êatemporarily appears in a weird°dONLNdtÄfl(ú6+color. Is there any way to get around this?°dONLNdBÄå** ___°dONLNdFò§2*:When you quit, RestoreDeviceClut is called to restore the °dONLNdÄò2§⁄(¿P"color table and an update event is°dONLNd£§∞¿(Ã6&called to redraw the screen. It’s the °dONLNd…§¿∞⁄)®:delay between the change in the color table and the update°dONLNd∞º“(ÿ6Vevent that causes the flash of incorrect colors to be displayed. This, unfortunately, °dONLNdZ∞“º⁄(ÿis°dONLNd]º»U(‰6 unavoidable.
  8816. °dONLNdj‡Ô´*';Restoring Finder desktop colors after using Palette Manager
  8817. °dONLNd¶Ô˚>* Written:°dONLNdØÔd˚à)L8/28/91°dONLNd∑˚](#6Last reviewed:°dONLNdΔ˚dÇ)L8/1/92°dONLNdÕæ(;6XAfter using the Macintosh Palette Manager, how do I restore the Finder’s desktop colors?°dONLNd&+** ___°dONLNd*7C∂*UThe Finder desktop’s colors are restored automatically on quitting applications that °dONLNd7∂C⁄(_‘use the°dONLNdáCO(k66Palette Manager. Colors aren’t restored automatically °dONLNdΩCO⁄)˝'when switching from your application to°dONLNdÂO[(w65another, but if that application needs a certain set °dONLNdO[⁄)Ë-of colors and uses the Palette Manager to get°dONLNdH[gâ(É6Gthem, then it’ll have them the moment it comes to the front. If you’re °dONLNdè[âg⁄(Éßconcerned about°dONLNdügs4(è6=applications that don’t use the Palette Manager, you can use °dONLNd‹g4s⁄(èRRestoreDeviceClut(gd:GDHandle),°dONLNd¸sç(õ6Qpassing the handle to the GDevice of the screen you want to reset, or nil if you °dONLNdMsç⁄(õ´want to reset all°dONLNd_ã∏(ß6of your devices. Passing nil °dONLNd|∏ã⁄)†4to RestoreDeviceClut is your best bet, as it is very°dONLNd±ãó?(≥6:straightforward, and resets all of your monitors. You may °dONLNdÎã?ó⁄(≥]not wish to do this, however,°dONLNd    ó£¥(ø6Tbecause RestoreDeviceClut is only available on machines with 32-bit color QuickDraw.°dONLNd^تà*ITo reset a screen’s GDevice for machines without 32-bit color QuickDraw, °dONLNdߨàª⁄(◊¶you will need to°dONLNd∏ª«](„6Gkeep track of the color table.When your application starts up, get the °dONLNdˇª]«⁄(„{GDevice’s color table and°dONLNd«”∂(Ô6#save it—you’ll need it later. This °dONLNd<«∂”⁄)û6value can be found at (**(**GDHandle).gdPMap).pmTable,°dONLNds”fl°(˚6Lwhere gdPMap is a PixMapHandle, and pmTable is a CTabHandle which tells you °dONLNdø”°fl⁄(˚ø the absolute°dONLNdÃflÎv(6Kcolors for this image. These data structures are found in Inside Macintosh °dONLNdflvÎ⁄(îVolume V, pages 52°dONLNd*ΘB(6and 119.°dONLNd3S*@Build your application’s “world” using the Palette Manager, and °dONLNdsS⁄(+qavoid low-level methods of°dONLNdé§(76Hchanging colors. When your application is about to quit and you want to °dONLNd÷§⁄(7¬ restore the°dONLNd‚'<(C6Aenvironment to its original state, get the color table you saved °dONLNd    #<'⁄(CZ!in the beginning. Convert this to°dONLNd    E'3w(O6Ha palette using CTab2Palette. Then set your window to this palette with °dONLNd    ç'w3⁄(OïSetPalette. This will°dONLNd    £3? ([6#cause the environment to update to °dONLNd    Δ3 ?⁄)≤8the original color table that you initially got from the°dONLNd    ˇ?KH(g6    GDevice. °dONLNd
  8818. ?HK⁄)0WIf the application that is behind your application is Palette Manager friendly, then it°dONLNd
  8819. `KW`(s6Bwill restore the environment to its palette. You may also want to °dONLNd
  8820. ¢K`W⁄(s~do this procedure at the°dONLNd
  8821. ªWcF(6:suspend event, as shown in the DTS sample MacApp program, °dONLNd
  8822. ıWFc⁄(dFracApp. One of the problems°dONLNd coA(ã6    that you °dONLNd cAo⁄))Pwon’t be able to solve this way involves multiple monitors. You won’t know which°dONLNd lo{≈(ó6%one to update. Only the monitor that °dONLNd ëo≈{⁄)≠9has the window that you’ve called ActivatePalette on will°dONLNd À{á;(£6update.°dONLNd ”ìü/*2If your application changes the color environment °dONLNd ì/ü⁄(ªMwith the Palette Manager, then°dONLNd $ü´Ä(«6RestoreDeviceClut is °dONLNd 9üÄ´⁄)hEcalled automatically when your application quits. This means that you ◊4◊˘
  8823. (Ï62) of 3(ÏõPalette Manager Q&AsˇL◊#ˇ ˇˇˇˇ#◊ 
  8824. IR,Times
  8825. .+Z-Developer Support Center(-Ê October 1992 /X/
  8826. °dONLNd<)m(EZ
  8827. shouldn’t °dONLNd
  8828. m)˛)1Qhave to worry about restoring the palette if you don’t want to. There is a catch,°dONLNd\)<5ä(QZ<however (there always is). When you use the SADE version of °dONLNdò)ä5˛(Q®MultiFinder (6.1b9), it°dONLNd∞5<Ac(]Z>prevents this from automatically happening. Other versions of °dONLNdÓ5cA˛(]Å MultiFinder don’t have this side°dONLNdA<MZ(iZeffect.
  8829. °dONLNde<t *':SetPalette cUpdates, NSetPalette, and window update events
  8830. °dONLNdRt<Äb* Written:°dONLNd[tàĨ)L9/26/91°dONLNdcÄ<åÅ(®ZLast reviewed:°dONLNdrÄàå¶)L8/1/92°dONLNdyò<§fi(¿ZUWhen I pass false in the cUpdates parameter to SetPalette, I still get update events °dONLNdŒòfi§˛(¿¸to that°dONLNd÷§<∞6(ÃZ2window when I modify its palette. What’s going on?°dONLNd    ∞<ºN* ___°dONLNd
  8831. »<‘£*KSetPalette’s cUpdates parameter controls whether color-table changes cause °dONLNdX»£‘˛(¡that window to get°dONLNdk‘<‡d(¸Z<update events only if that window is NOT frontmost. If that °dONLNdß‘d‡˛(¸Çwindow is frontmost, then any°dONLNd≈‡<Ïé(ZKchanges to its palette causes it to get an update event regardless of what °dONLNd‡éÏ˛(¨the cUpdates parameter°dONLNd'Ï<¯í(Zis. When you call °dONLNd9Ïí¯˛)VJSetEntryColor and then ActivatePalette for your front-most window, it gets°dONLNdѯ<fl( Z!an update event because it’s the °dONLNd•¯fl˛)£5front-most window even though you passed false in the°dONLNd€<˘(,Z&cUpdates parameter. Another important °dONLNd˘˛)Ω7point is that windows that don’t have palettes also get°dONLNd9<g(8Z>update events even when another window’s palette is activated.°dONLNdx(<4A*6Fortunately, system software version 6.0.2 introduced °dONLNdÆ(A4˛(P_&the NSetPalette routine, which you can°dONLNd’4<@¥(\ZLfind documented in the Macintosh Technical Note “Palette Manager Changes in °dONLNd!4¥@˛(\“System 6.0.2,”°dONLNd0@<LP(hZand °dONLNd4@PL˛)Ton page 20-20 in the revamped Palette Manager chapter of Inside Macintosh Volume VI.°dONLNdâL<Xì(tZMThis variation of SetPalette gives you a lot more flexibility in controlling °dONLNd÷LìX˛(t±whether your window°dONLNdÍX<dY(ÄZ7gets an update event than SetPalette does. If you pass °dONLNd!XYd˛(ÄwpmAllUpdates in the nCUpdates°dONLNd?d<pk(åZ@parameter, then that window gets an update event when either it °dONLNddkp˛(åâor another window’s palette is°dONLNdûp<|^(òZ;activated. If you pass pmFgUpdates, then it gets an update °dONLNdŸp^|˛(ò|!event when a palette is activated°dONLNd˚|<àT(§Zonly °dONLNd|Tà˛)\if it’s the front-most window (in effect, it only gets an update event if its own palette is°dONLNd]à<î’(∞ZTactivated). If you pass pmBkUpdates, then it gets an update event when a palette is °dONLNd±à’î˛(∞Û    activated°dONLNdªî<†ù(ºZonly if it’s not the °dONLNd–îù†˛)aEfront-most window (in effect, it only gets an update event if another°dONLNd†<¨í(»Zwindow’s palette °dONLNd'†í¨˛)VFis activated). If you pass pmNoUpdates, then that window never gets an°dONLNdn¨<∏—(‘ZUupdate event from any window’s palette being activated, including that window itself. ◊X◊
  8832. (ÏZPalette Manager Q&As(Ï3) of 3ˇf◊#ˇ ˇˇˇˇ#◊†Ç 
  8833. /ZÅ
  8834.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8835. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8836. .R≈R…x(+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8837. Ω({íDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8838. 0Ûe(UÎ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8839.     û?+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8840. ze(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8841. IR.°dONLNdn<Å[(õZPicture Comments—The Real Deal
  8842. °dONLNdÄ<èr*Imaging°dONLNd'Ävè˛(´îM.IM.PictComments
  8843. °dONLNd9õ<ßt(√Z Revised by:°dONLNdEõÑß )H
  8844. Joseph Maurer°dONLNdSõæß˛(√‹ October 1992°dONLNd`ß<≥q(œZ Written by:°dONLNdlßÑ≥–)HGinger Jernigan°dONLNd|ß±≥˛(œœ
  8845. November 1986°dONLNdäø<À‹(ÁZChanges since March 1988: °dONLNd§ø‹À>)†This Note (formerly °dONLNd∏ø>ÀÚ)b&titled “Optimizing for the LaserWriter°dONLNdfiøÚÀ˛)¥—°dONLNdflÀ<◊%(ÛZ-PicComments”) describes the picture comments °dONLNd À%◊˛)È,defined and interpreted by the Apple printer°dONLNd9◊<„(ˇZdrivers. Most °dONLNdG◊„˛)CNof the picture comments are specific to PostScript, but we renamed the Note to°dONLNdñ„<Ôû( ZLemphasize that LaserWriter printers are not necessarily PostScript devices, °dONLNd‚„ûÔ˛( ºand that QuickDraw°dONLNdıÔ<˚—(ZLprinter drivers may implement their own picture comment handling. This Note °dONLNdAÔ—˚˛(Ôhas been°dONLNdJ˚< (#ZUcompletely rewritten and incorporates all additional insights gained during the last °dONLNdü˚ ˛(#Ë
  8846. few years.°dONLNd™<`(/ZWe are °dONLNd±`˛)$Qalso much more determined now to discourage the use of obsolete and problem-laden°dONLNd<(;Z-(although still supported) picture comments, °dONLNd0˛)Ÿ,and we carefully point out known problems or°dONLNd]<+ƒ(GZlimitations of each comment. VXV
  8847. °dONLNdzD<Sè*( Introduction
  8848. °dONLNdá`<lR*The ,
  8849. Courier°dONLNdã_RkÉ)QDProcs°dONLNdí`Él¿)1
  8850.  record (see °dONLNdü`¿l)=Inside Macintosh°dONLNdØ`l∑)R" Volume I, page 197) reflects the °dONLNd—`∑l˛)•foundations of°dONLNd‡m<yì(ïZthe architecture of °dONLNdÙmìyÁ)WQuickDraw. The °dONLNdlÁx4)T commentProc°dONLNdm4y˛)M+ field points to a procedure that processes°dONLNd:z<Ü^(¢Z;picture comments, as included in a picture by means of the °dONLNduy^Ö§(¢|
  8851. PicComment°dONLNdz§Ü·)F  procedure (°dONLNdãz·Ü˛)=Inside°dONLNdíÜ<ím(ÆZ    Macintosh°dONLNdõÜmí»)1 Volume I, page °dONLNd´Ü»í˛)[>189). This allows applications to include application-specific°dONLNdÍí<û"(∫Z3additional information in the pictures they create.°dONLNd´<∑R*The °dONLNd"™R∂É)QDProcs°dONLNd)´É∑G)1) record also is the key to understanding °dONLNdR´G∑˛)ƒ#how Macintosh printer drivers work.°dONLNdv∏<ƒ¬(‡ZWhen the application calls °dONLNdë∑¬√)Ü
  8852. PrOpenPage°dONLNdõ∏ƒo)F and draws into the °dONLNdØ∏oƒ˛)gprinting grafPort, the printer°dONLNdŒ≈<—Z(ÌZ9driver collects the drawing commands by hooking into the °dONLNdƒZ–ã(ÌxQDProcs°dONLNd≈ã—ÿ)1 of the printing °dONLNd≈ÿ—˛)Mport. In°dONLNd(“<fio(˙Z particular, °dONLNd4“ofiÎ)3if an application calls the °dONLNdP—Λ1)|
  8853. PicComment°dONLNdZ“1fi˛)F* procedure while drawing into the printing°dONLNdÖfi<Í(Z_grafPort, the printer driver gets a chance to capture and process the information contained in °dONLNd‰fiͲ(the°dONLNdËÍ<ˆX(Zkind°dONLNdÏÎX˜o) and °dONLNdÒÍoˆµ)
  8854. dataHandle°dONLNd˚ε˜Ô)F  parameters.°dONLNd<Œ(+ZDuring the development of the °dONLNd&Œ˛)í@original LaserWriter driver, it became obvious that applications°dONLNdg<:(7Z7should be able to take advantage of certain PostScript °dONLNdû:˛)˛)features that were not accessible through°dONLNd»<'¬(CZstandard QuickDraw calls, °dONLNd‚¬'˛)Ü@such as rotated text and graphics, dashed lines, fractional line°dONLNd#'<3Å(OZCwidths, and smoothed polygons. Also, certain applications needed a °dONLNdf'Å3˛(Oüway to transmit their own°dONLNdÄ3<?ü([ZJnative PostScript instructions to the printer. Picture comments seemed to °dONLNd 3ü?˛([Ωbe the ideal vehicle°dONLNdfl?<K—(gZ!for providing these capabilities.°dONLNd    W<cb*?Unfortunately, there are conflicts with the device-independent °dONLNd    @Wbc˛(Ä nature of the Macintosh Printing°dONLNd    ac<o‰(ãZ$Manager architecture. In this Note, °dONLNd    Öc‰o˛)®8we still want to document picture comments as completely°dONLNd    æo<{∂(óZand correctly as possible; °dONLNd    Ÿo∂{˛)zDand we want to tell you how to use the best of their features, while°dONLNd
  8855. {<áu(£ZBmaintaining the important goal of device-independent printing and °dONLNd
  8856. `{uá˛(£ìall- purpose PICTs. (This is°dONLNd
  8857. }á<ìfi(ØZ#why it has such a painful history!) ◊X◊
  8858. *=Picture Comments—The Real Deal(Ïˇ1) of 26ˇ°¿Ù%%DSIDICT:_cv
  8859. currentdict /bu known {bu}if
  8860. userdict /_cv known not{userdict /_cv 30 dict put}if
  8861. _cv begin
  8862. /bdf{bind def}bind def
  8863. currentscreen/cs exch def/ca exch def/cf exch def
  8864. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8865. /ss{//cf //ca //cs setscreen}bdf
  8866. /stg{ss setgray}bdf
  8867. /strgb{ss setrgbcolor}bdf
  8868. /stcmyk{ss cvcmyk}bdf
  8869. /min1{dup 0 eq{pop 1}if}bdf
  8870. end
  8871. currentdict /bn known {bn}if
  8872. †øñ◊#ˇ ˇˇˇˇ#◊ 
  8873. IR,Times
  8874. .+6-Macintosh Technical Notes /4/˘
  8875. °dONLNd)Î**First, we give an overview of the picture °dONLNd*Î)⁄)”,comments as currently implemented by Apple’s°dONLNdW)5z(Q6printer drivers. This °dONLNdm)z5⁄)bFleads us immediately to the problem section “Cohabitation of QuickDraw°dONLNd¥5A˛(]6.and PostScript,” which also shows how to keep °dONLNd‚5˛A⁄)Ê,the QuickDraw and PostScript graphics states°dONLNdAMÃ(i6Zsynchronized during printing. Finally, we discuss all the picture comments by subject, in °dONLNdiAÃM⁄(iÍthe°dONLNdmMYú(u6order suggested by Table 1.
  8876. °dONLNdâqÄ›*'Picture Comments Repertoire
  8877. °dONLNd•åòë*LThe following picture comments are recognized by all PostScript LaserWriter °dONLNdÒåëò⁄(¥Ødrivers version°dONLNdò§W(¿63.1 and later.°dONLNd∞kºá+S/Table 1-PostScript LaserWriter Picture Comments°dONLNdB«.”J(ÔLType°dONLNdG«ç”©)_Kind°dONLNdL«∫”Ô)-    Data Size°dONLNdV«”)HData°dONLNd[«J”ã)H Description
  8878.     °dONLNdh‡.ÎV(L    TextBegin°dONLNdr‡çÎú)_150°dONLNdv‡“Î◊)E6°dONLNdx‡Î.)0
  8879. TTxtPicRec°dONLNdɇJÎî)HBegin text function°dONLNdòÏ.˜M(LTextEnd°dONLNd†Ïç˜ú)_151°dONLNd§Ï“˜◊)E0°dONLNd¶Ï˜)0NIL°dONLNd™ÏJ˜ã)HEnd text function°dONLNdΩ¯.](L StringBegin°dONLNd…¯çú)_152°dONLNdÕ¯“◊)E0°dONLNdœ¯)0NIL°dONLNd”¯J´)HBegin string delimitation°dONLNdÓ.T(+L    StringEnd°dONLNd¯çú)_153°dONLNd¸“◊)E0°dONLNd˛)0NIL°dONLNdJ¢)HEnd string delimitation°dONLNd.X(7L
  8880. TextCenter°dONLNd%çú)_154°dONLNd)“◊)E8°dONLNd+-)0
  8881. TTxtCenter°dONLNd6JØ)HOffset to center of rotation°dONLNdT'.2e(NL
  8882. LineLayoutOff°dONLNdb'ç2ú)_155°dONLNdf'“2◊)E0°dONLNdh'2)0NIL°dONLNdl'J2¡)H Turn LaserWriter line layout off°dONLNdé3.>d(ZL LineLayoutOn°dONLNdõ3ç>ú)_156°dONLNdü3“>◊)E0°dONLNd°3>)0NIL°dONLNd•3J>¿)HTurn LaserWriter line layout on°dONLNd≈?J(f6#°d